parent
db94a8ed19
commit
b520b0cb22
|
|
@ -93,13 +93,12 @@ namespace MvcSample.Web
|
|||
return View("MyView", user);
|
||||
}
|
||||
|
||||
[FromServices]
|
||||
public IHostingEnvironment HostingEnvironment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Action that shows multiple file upload.
|
||||
/// </summary>
|
||||
public async Task<ActionResult> PostFile(IList<IFormFile> files)
|
||||
public async Task<ActionResult> PostFile(
|
||||
[FromServices] IHostingEnvironment hostingEnvironment,
|
||||
IList<IFormFile> files)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
|
|
@ -108,7 +107,7 @@ namespace MvcSample.Web
|
|||
|
||||
foreach (var f in files)
|
||||
{
|
||||
await f.SaveAsAsync(Path.Combine(HostingEnvironment.WebRootPath, "test-file" + files.IndexOf(f)));
|
||||
await f.SaveAsAsync(Path.Combine(hostingEnvironment.WebRootPath, "test-file" + files.IndexOf(f)));
|
||||
}
|
||||
return View();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,25 +7,9 @@ using Microsoft.AspNet.Mvc.ModelBinding;
|
|||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies that a parameter or property should be bound using the request services.
|
||||
/// Specifies that an action parameter should be bound using the request services.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// In this example, the LocationService property on the VehicleWithDealerViewModel class
|
||||
/// will be bound to the value resolved for the ILocationService service from the request services.
|
||||
///
|
||||
/// <code>
|
||||
/// public class VehicleWithDealerViewModel
|
||||
/// {
|
||||
/// [FromServices]
|
||||
/// public ILocationService LocationService { get; set; }
|
||||
///
|
||||
/// public void Update()
|
||||
/// {
|
||||
/// LocationService.Update();
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
///
|
||||
/// In this example an implementation of IProductModelRequestService is registered as a service.
|
||||
/// Then in the GetProduct action, the parameter is bound to an instance of IProductModelRequestService
|
||||
/// which is resolved from the the request services.
|
||||
|
|
@ -38,10 +22,10 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
||||
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
|
||||
public class FromServicesAttribute : Attribute, IBindingSourceMetadata
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public BindingSource BindingSource { get { return BindingSource.Services; } }
|
||||
public BindingSource BindingSource => BindingSource.Services;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Mvc;
|
|||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.AspNet.Mvc.WebApiCompatShim;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
|
@ -22,6 +23,9 @@ namespace System.Web.Http
|
|||
public abstract class ApiController : IDisposable
|
||||
{
|
||||
private HttpRequestMessage _request;
|
||||
private IModelMetadataProvider _metadataProvider;
|
||||
private IObjectModelValidator _objectValidator;
|
||||
private IUrlHelper _urlHelper;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the action context.
|
||||
|
|
@ -52,12 +56,42 @@ namespace System.Web.Http
|
|||
/// Gets the <see cref="IModelMetadataProvider"/>.
|
||||
/// </summary>
|
||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||
[FromServices]
|
||||
public IModelMetadataProvider MetadataProvider { get; set; }
|
||||
public IModelMetadataProvider MetadataProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_metadataProvider == null)
|
||||
{
|
||||
_metadataProvider = Context?.RequestServices?.GetRequiredService<IModelMetadataProvider>();
|
||||
}
|
||||
|
||||
return _metadataProvider;
|
||||
}
|
||||
set
|
||||
{
|
||||
_metadataProvider = value;
|
||||
}
|
||||
}
|
||||
|
||||
[FromServices]
|
||||
public IObjectModelValidator ObjectValidator { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IObjectModelValidator"/>.
|
||||
/// </summary>
|
||||
public IObjectModelValidator ObjectValidator
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_objectValidator == null)
|
||||
{
|
||||
_objectValidator = Context?.RequestServices?.GetRequiredService<IObjectModelValidator>();
|
||||
}
|
||||
|
||||
return _objectValidator;
|
||||
}
|
||||
set
|
||||
{
|
||||
_objectValidator = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets model state after the model binding process. This ModelState will be empty before model binding
|
||||
|
|
@ -96,8 +130,22 @@ namespace System.Web.Http
|
|||
/// Gets a factory used to generate URLs to other APIs.
|
||||
/// </summary>
|
||||
/// <remarks>The setter is intended for unit testing purposes only.</remarks>
|
||||
[FromServices]
|
||||
public IUrlHelper Url { get; set; }
|
||||
public IUrlHelper Url
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_urlHelper == null)
|
||||
{
|
||||
_urlHelper = Context?.RequestServices?.GetRequiredService<IUrlHelper>();
|
||||
}
|
||||
|
||||
return _urlHelper;
|
||||
}
|
||||
set
|
||||
{
|
||||
_urlHelper = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current principal associated with this request.
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var modelType = typeof(BaseViewModel);
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == "BaseProperty");
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == nameof(BaseModel.BaseProperty));
|
||||
|
||||
// Act
|
||||
var attributes = ModelAttributes.GetAttributesForProperty(modelType, property);
|
||||
|
|
@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var modelType = typeof(BaseViewModel);
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == "TestProperty");
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == nameof(BaseModel.TestProperty));
|
||||
|
||||
// Act
|
||||
var attributes = ModelAttributes.GetAttributesForProperty(modelType, property);
|
||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var modelType = typeof(DerivedViewModel);
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == "BaseProperty");
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == nameof(BaseModel.BaseProperty));
|
||||
|
||||
// Act
|
||||
var attributes = ModelAttributes.GetAttributesForProperty(modelType, property);
|
||||
|
|
@ -82,7 +82,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var modelType = typeof(DerivedViewModel);
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == "TestProperty");
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == nameof(BaseModel.TestProperty));
|
||||
|
||||
// Act
|
||||
var attributes = ModelAttributes.GetAttributesForProperty(modelType, property);
|
||||
|
|
@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var modelType = typeof(DerivedViewModel);
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == "VirtualProperty");
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == nameof(BaseModel.VirtualProperty));
|
||||
|
||||
// Act
|
||||
var attributes = ModelAttributes.GetAttributesForProperty(modelType, property);
|
||||
|
|
@ -120,17 +120,17 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
{
|
||||
// Arrange
|
||||
var modelType = typeof(DerivedViewModel);
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == "Calculator");
|
||||
var property = modelType.GetRuntimeProperties().FirstOrDefault(p => p.Name == nameof(BaseModel.RouteValue));
|
||||
|
||||
// Act
|
||||
var attributes = ModelAttributes.GetAttributesForProperty(modelType, property);
|
||||
|
||||
// Assert
|
||||
Assert.Single(attributes.Attributes.OfType<RequiredAttribute>());
|
||||
Assert.Single(attributes.Attributes.OfType<FromServicesAttribute>());
|
||||
Assert.Single(attributes.Attributes.OfType<FromRouteAttribute>());
|
||||
|
||||
Assert.Single(attributes.PropertyAttributes.OfType<RequiredAttribute>());
|
||||
Assert.Single(attributes.PropertyAttributes.OfType<FromServicesAttribute>());
|
||||
Assert.Single(attributes.PropertyAttributes.OfType<FromRouteAttribute>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -191,8 +191,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
[Required]
|
||||
public virtual int VirtualProperty { get; set; }
|
||||
|
||||
[FromServices]
|
||||
public ICalculator Calculator { get; set; }
|
||||
[FromRoute]
|
||||
public string RouteValue { get; set; }
|
||||
}
|
||||
|
||||
private class DerivedModel : BaseModel
|
||||
|
|
@ -218,7 +218,7 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
public string BaseProperty { get; set; }
|
||||
|
||||
[Required]
|
||||
public ICalculator Calculator { get; set; }
|
||||
public string RouteValue { get; set; }
|
||||
}
|
||||
|
||||
[ModelMetadataType(typeof(DerivedModel))]
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ 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)
|
||||
{
|
||||
|
|
@ -40,6 +39,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
var response = await Client.SendAsync(request);
|
||||
|
||||
// Assert
|
||||
response.EnsureSuccessStatusCode();
|
||||
var body = (await response.Content.ReadAsStringAsync()).Trim();
|
||||
Assert.Equal(requestId, body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,176 +258,6 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
Assert.True(modelState.IsValid);
|
||||
}
|
||||
|
||||
private class Order2
|
||||
{
|
||||
public int ProductId { get; set; }
|
||||
|
||||
public Person2 Customer { get; set; }
|
||||
}
|
||||
|
||||
private class Person2
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
[FromServices]
|
||||
public IActionBindingContextAccessor BindingContext { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MutableObjectModelBinder_BindsNestedPOCO_WithServicesModelBinder_WithPrefix_Success()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "parameter",
|
||||
ParameterType = typeof(Order2)
|
||||
};
|
||||
|
||||
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||
{
|
||||
request.QueryString = new QueryString("?parameter.Customer.Name=bill");
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
var model = Assert.IsType<Order2>(modelBindingResult.Model);
|
||||
Assert.NotNull(model.Customer);
|
||||
Assert.Equal("bill", model.Customer.Name);
|
||||
Assert.NotNull(model.Customer.BindingContext);
|
||||
|
||||
Assert.Equal(1, modelState.Count);
|
||||
Assert.Equal(0, modelState.ErrorCount);
|
||||
Assert.True(modelState.IsValid);
|
||||
|
||||
var entry = Assert.Single(modelState, e => e.Key == "parameter.Customer.Name").Value;
|
||||
Assert.Equal("bill", entry.AttemptedValue);
|
||||
Assert.Equal("bill", entry.RawValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MutableObjectModelBinder_BindsNestedPOCO_WithServicesModelBinder_WithEmptyPrefix_Success()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "parameter",
|
||||
ParameterType = typeof(Order2)
|
||||
};
|
||||
|
||||
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||
{
|
||||
request.QueryString = new QueryString("?Customer.Name=bill");
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
var model = Assert.IsType<Order2>(modelBindingResult.Model);
|
||||
Assert.NotNull(model.Customer);
|
||||
Assert.Equal("bill", model.Customer.Name);
|
||||
Assert.NotNull(model.Customer.BindingContext);
|
||||
|
||||
Assert.Equal(1, modelState.Count);
|
||||
Assert.Equal(0, modelState.ErrorCount);
|
||||
Assert.True(modelState.IsValid);
|
||||
|
||||
var entry = Assert.Single(modelState, e => e.Key == "Customer.Name").Value;
|
||||
Assert.Equal("bill", entry.AttemptedValue);
|
||||
Assert.Equal("bill", entry.RawValue);
|
||||
}
|
||||
|
||||
// We don't provide enough data in this test for the 'Person' model to be created. So even though there is
|
||||
// a [FromServices], it won't be used.
|
||||
[Fact]
|
||||
public async Task MutableObjectModelBinder_BindsNestedPOCO_WithServicesModelBinder_WithPrefix_PartialData()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "parameter",
|
||||
ParameterType = typeof(Order2)
|
||||
};
|
||||
|
||||
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||
{
|
||||
request.QueryString = new QueryString("?parameter.ProductId=10");
|
||||
SetJsonBodyContent(request, AddressBodyContent);
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
var model = Assert.IsType<Order2>(modelBindingResult.Model);
|
||||
Assert.Null(model.Customer);
|
||||
Assert.Equal(10, model.ProductId);
|
||||
|
||||
Assert.Equal(1, modelState.Count);
|
||||
Assert.Equal(0, modelState.ErrorCount);
|
||||
Assert.True(modelState.IsValid);
|
||||
|
||||
var entry = Assert.Single(modelState, e => e.Key == "parameter.ProductId").Value;
|
||||
Assert.Equal("10", entry.AttemptedValue);
|
||||
Assert.Equal("10", entry.RawValue);
|
||||
}
|
||||
|
||||
// We don't provide enough data in this test for the 'Person' model to be created. So even though there is
|
||||
// a [FromServices], it won't be used.
|
||||
[Fact]
|
||||
public async Task MutableObjectModelBinder_BindsNestedPOCO_WithServicesModelBinder_WithPrefix_NoData()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "parameter",
|
||||
ParameterType = typeof(Order2)
|
||||
};
|
||||
|
||||
// Need to have a key here so that the MutableObjectModelBinder will recurse to bind elements.
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||
{
|
||||
request.QueryString = new QueryString("?");
|
||||
SetJsonBodyContent(request, AddressBodyContent);
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
var model = Assert.IsType<Order2>(modelBindingResult.Model);
|
||||
Assert.Null(model.Customer);
|
||||
|
||||
Assert.Equal(0, modelState.Count);
|
||||
Assert.Equal(0, modelState.ErrorCount);
|
||||
Assert.True(modelState.IsValid);
|
||||
}
|
||||
|
||||
private class Order3
|
||||
{
|
||||
public int ProductId { get; set; }
|
||||
|
|
@ -1489,9 +1319,6 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
{
|
||||
[FromBody]
|
||||
public Address1 Address { get; set; }
|
||||
|
||||
[FromServices]
|
||||
public IActionBindingContextAccessor BindingContext { get; set; }
|
||||
}
|
||||
|
||||
// If a nested POCO object has all properties bound from a greedy source, then it should be populated
|
||||
|
|
@ -1524,7 +1351,6 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
|
||||
var model = Assert.IsType<Order9>(modelBindingResult.Model);
|
||||
Assert.NotNull(model.Customer);
|
||||
Assert.NotNull(model.Customer.BindingContext);
|
||||
Assert.NotNull(model.Customer.Address);
|
||||
Assert.Equal(AddressStreetContent, model.Customer.Address.Street);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,90 +13,6 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
{
|
||||
public class ServicesModelBinderIntegrationTest
|
||||
{
|
||||
private class Person
|
||||
{
|
||||
public Address Address { get; set; }
|
||||
}
|
||||
|
||||
private class Address
|
||||
{
|
||||
// Using a service type already in defaults.
|
||||
[FromServices]
|
||||
public JsonOutputFormatter OutputFormatter { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindPropertyFromService_WithData_WithPrefix_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
},
|
||||
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
Assert.NotNull(boundPerson.Address.OutputFormatter);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
Assert.Empty(modelState.Keys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindPropertyFromService_WithData_WithEmptyPrefix_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo(),
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
Assert.NotNull(boundPerson.Address.OutputFormatter);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
|
||||
// For non user bound models there should be no entry in model state.
|
||||
Assert.Empty(modelState);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindParameterFromService_WithData_GetsBound()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,9 +10,12 @@ namespace ActionResultsWebSite
|
|||
{
|
||||
public class ActionResultsVerificationController : Controller
|
||||
{
|
||||
public ActionResultsVerificationController(GuidLookupService guidLookupService)
|
||||
{
|
||||
GuidLookupService = guidLookupService;
|
||||
}
|
||||
|
||||
[FromServices]
|
||||
public GuidLookupService Service { get; set; }
|
||||
public GuidLookupService GuidLookupService { get; }
|
||||
|
||||
public IActionResult Index([FromBody]DummyClass test)
|
||||
{
|
||||
|
|
@ -107,7 +110,7 @@ namespace ActionResultsWebSite
|
|||
public bool GetDisposeCalled(string guid)
|
||||
{
|
||||
bool value;
|
||||
if (Service.IsDisposed.TryGetValue(guid, out value))
|
||||
if (GuidLookupService.IsDisposed.TryGetValue(guid, out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
|
@ -131,7 +134,7 @@ namespace ActionResultsWebSite
|
|||
|
||||
private DisposableType CreateDisposableType(string guid)
|
||||
{
|
||||
return new DisposableType(Service, guid);
|
||||
return new DisposableType(GuidLookupService, guid);
|
||||
}
|
||||
|
||||
private class DisposableType : IDisposable
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@ namespace ActivatorWebSite
|
|||
{
|
||||
public class PlainController
|
||||
{
|
||||
[FromServices]
|
||||
public MyService Service { get; set; }
|
||||
|
||||
[ActionContext]
|
||||
public ActionContext ActionContext { get; set; }
|
||||
|
||||
|
|
@ -18,12 +15,12 @@ namespace ActivatorWebSite
|
|||
|
||||
public HttpResponse Response => ActionContext.HttpContext.Response;
|
||||
|
||||
public IActionResult Index()
|
||||
public IActionResult Index([FromServices] MyService service)
|
||||
{
|
||||
Response.Headers["X-Fake-Header"] = "Fake-Value";
|
||||
|
||||
var value = Request.Query["foo"];
|
||||
return new ContentResult { Content = Service.Random + "|" + value };
|
||||
return new ContentResult { Content = service.Random + "|" + value };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace ApiExplorerWebSite
|
||||
{
|
||||
public interface IOrderRepository
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -7,9 +7,6 @@ namespace ApiExplorerWebSite
|
|||
{
|
||||
public class OrderDTO
|
||||
{
|
||||
[FromServices]
|
||||
public IOrderRepository Repository { get; set; }
|
||||
|
||||
public string CustomerId { get; set; }
|
||||
|
||||
[FromHeader(Name = "Referrer")]
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@ namespace HtmlGenerationWebSite.Controllers
|
|||
{
|
||||
public class Catalog_CacheTagHelperController : Controller
|
||||
{
|
||||
[FromServices]
|
||||
public ProductsService ProductsService { get; set; }
|
||||
|
||||
[HttpGet("/catalog")]
|
||||
public IActionResult Splash(int categoryId, int correlationId, [FromHeader] string locale)
|
||||
{
|
||||
|
|
@ -75,9 +72,9 @@ namespace HtmlGenerationWebSite.Controllers
|
|||
}
|
||||
|
||||
[HttpPost("/categories/update-products")]
|
||||
public void UpdateCategories()
|
||||
public void UpdateCategories([FromServices] ProductsService productsService)
|
||||
{
|
||||
ProductsService.UpdateProducts();
|
||||
productsService.UpdateProducts();
|
||||
}
|
||||
|
||||
[HttpGet("/catalog/GetDealPercentage/{dealPercentage}")]
|
||||
|
|
|
|||
|
|
@ -7,9 +7,6 @@ namespace ModelBindingWebSite
|
|||
{
|
||||
public class CalculatorContext
|
||||
{
|
||||
[FromServices]
|
||||
public ICalculator Calculator { get; set; }
|
||||
|
||||
public int Left { get; set; }
|
||||
|
||||
public int Right { get; set; }
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ namespace ModelBindingWebSite.Controllers
|
|||
{
|
||||
public class FromServices_CalculatorController : Controller
|
||||
{
|
||||
public int Calculate(CalculatorContext context)
|
||||
public int Calculate(CalculatorContext context, [FromServices] ICalculator calculator)
|
||||
{
|
||||
return context.Calculator.Operation(context.Operator, context.Left, context.Right);
|
||||
return calculator.Operation(context.Operator, context.Left, context.Right);
|
||||
}
|
||||
|
||||
public int Add(int left, int right, [FromServices] ICalculator calculator)
|
||||
|
|
@ -17,9 +17,9 @@ namespace ModelBindingWebSite.Controllers
|
|||
return calculator.Operation('+', left, right);
|
||||
}
|
||||
|
||||
public int CalculateWithPrecision(DefaultCalculatorContext context)
|
||||
public int CalculateWithPrecision(DefaultCalculatorContext context, [FromServices] ICalculator calculator)
|
||||
{
|
||||
return context.Calculator.Operation(context.Operator, context.Left, context.Right);
|
||||
return calculator.Operation(context.Operator, context.Left, context.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,11 @@ namespace ModelBindingWebSite.Controllers
|
|||
private IHtmlHelper<Person> _personHelper;
|
||||
private bool _activated;
|
||||
|
||||
[FromServices]
|
||||
public RoundtripController(IHtmlHelper<Person> personHelper)
|
||||
{
|
||||
_personHelper = personHelper;
|
||||
}
|
||||
|
||||
public IHtmlHelper<Person> PersonHelper
|
||||
{
|
||||
get
|
||||
|
|
@ -35,15 +39,11 @@ namespace ModelBindingWebSite.Controllers
|
|||
TextWriter.Null,
|
||||
new HtmlHelperOptions());
|
||||
|
||||
((ICanHasViewContext)PersonHelper).Contextualize(context);
|
||||
((ICanHasViewContext)_personHelper).Contextualize(context);
|
||||
}
|
||||
|
||||
return _personHelper;
|
||||
}
|
||||
set
|
||||
{
|
||||
_personHelper = value;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetPerson()
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@ namespace ModelBindingWebSite.Controllers
|
|||
[Route("Validation/[Action]")]
|
||||
public class ValidationController : Controller
|
||||
{
|
||||
[FromServices]
|
||||
public ITestService ControllerService { get; set; }
|
||||
|
||||
public object AvoidRecursive(SelfishPerson selfishPerson)
|
||||
{
|
||||
return ModelState.IsValid;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ namespace ModelBindingWebSite
|
|||
return PartialView("UpdateVehicle", model);
|
||||
}
|
||||
|
||||
model.Update();
|
||||
return PartialView("UpdateSuccessful", model);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ModelBindingWebSite
|
||||
{
|
||||
public interface ITestService
|
||||
{
|
||||
[Required]
|
||||
string NeverBound { get; set; }
|
||||
|
||||
bool Test();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using ModelBindingWebSite.ViewModels;
|
||||
|
||||
namespace ModelBindingWebSite.Services
|
||||
{
|
||||
public interface ILocationService
|
||||
{
|
||||
bool IsValidMakeForRegion(string make, string region);
|
||||
|
||||
bool Update(VehicleWithDealerViewModel model);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using ModelBindingWebSite.ViewModels;
|
||||
|
||||
namespace ModelBindingWebSite.Services
|
||||
{
|
||||
public class LocationService : ILocationService
|
||||
{
|
||||
public bool Update(VehicleWithDealerViewModel viewModel)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsValidMakeForRegion(string make, string region)
|
||||
{
|
||||
switch (make)
|
||||
{
|
||||
case "Acme":
|
||||
return region == "NW" || "region" == "South Central";
|
||||
case "FastCars":
|
||||
return region != "Central";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
// 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.Extensions.DependencyInjection;
|
||||
using ModelBindingWebSite.Models;
|
||||
using ModelBindingWebSite.Services;
|
||||
|
|
@ -32,7 +31,6 @@ namespace ModelBindingWebSite
|
|||
services.AddSingleton<ITestService, TestService>();
|
||||
|
||||
services.AddTransient<IVehicleService, VehicleService>();
|
||||
services.AddTransient<ILocationService, LocationService>();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app)
|
||||
|
|
|
|||
|
|
@ -1,18 +1,10 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace ModelBindingWebSite
|
||||
{
|
||||
public class TestService : ITestService
|
||||
{
|
||||
[Required]
|
||||
public string NeverBound { get; set; }
|
||||
|
||||
public bool Test()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public bool Test() => true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,8 +38,9 @@ namespace ModelBindingWebSite.ViewModels
|
|||
{
|
||||
if (InspectedDates.Any(d => d.Year > Year))
|
||||
{
|
||||
yield return new ValidationResult("Inspection date cannot be later than year of manufacture.",
|
||||
new[] { nameof(InspectedDates) });
|
||||
yield return new ValidationResult(
|
||||
"Inspection date cannot be later than year of manufacture.",
|
||||
new[] { nameof(InspectedDates) });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using ModelBindingWebSite.Services;
|
||||
|
||||
namespace ModelBindingWebSite.ViewModels
|
||||
{
|
||||
|
|
@ -17,23 +16,28 @@ namespace ModelBindingWebSite.ViewModels
|
|||
[FromBody]
|
||||
public VehicleViewModel Vehicle { get; set; }
|
||||
|
||||
[FromServices]
|
||||
public ILocationService LocationService { get; set; }
|
||||
|
||||
[FromHeader(Name = "X-TrackingId")]
|
||||
public string TrackingId { get; set; } = "default-tracking-id";
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (!LocationService.IsValidMakeForRegion(Vehicle.Make, Dealer.Location))
|
||||
if (!IsValidMakeForRegion(Vehicle.Make, Dealer.Location))
|
||||
{
|
||||
yield return new ValidationResult("Make is invalid for region.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
public bool IsValidMakeForRegion(string make, string region)
|
||||
{
|
||||
LocationService.Update(this);
|
||||
switch (make)
|
||||
{
|
||||
case "Acme":
|
||||
return region == "NW" || "region" == "South Central";
|
||||
case "FastCars":
|
||||
return region != "Central";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,12 +40,6 @@ namespace RequestServicesWebSite
|
|||
return View("ViewComponent");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public string FromModelProperty(RequestModel requestContext)
|
||||
{
|
||||
return requestContext.RequestIdService.RequestId;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public string FromActionArgument([FromServices] RequestIdService requestIdService)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,13 +8,10 @@ namespace RequestServicesWebSite
|
|||
[Route("RequestScoped/[action]")]
|
||||
public class RequestScopedServiceController
|
||||
{
|
||||
[FromServices]
|
||||
public RequestIdService RequestIdService { get; set; }
|
||||
|
||||
[HttpGet]
|
||||
public string FromController()
|
||||
public string FromController([FromServices] RequestIdService requestIdService)
|
||||
{
|
||||
return RequestIdService.RequestId;
|
||||
return requestIdService.RequestId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. 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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -15,9 +15,6 @@ namespace WebApiCompatShimWebSite
|
|||
{
|
||||
public class BasicApiController : ApiController
|
||||
{
|
||||
[FromServices]
|
||||
public IOptions<WebApiCompatShimOptions> OptionsAccessor { get; set; }
|
||||
|
||||
// Verifies property activation
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> WriteToHttpContext()
|
||||
|
|
@ -43,9 +40,9 @@ namespace WebApiCompatShimWebSite
|
|||
|
||||
// Verifies the default options configure formatters correctly.
|
||||
[HttpGet]
|
||||
public string[] GetFormatters()
|
||||
public string[] GetFormatters([FromServices] IOptions<WebApiCompatShimOptions> optionsAccessor)
|
||||
{
|
||||
return OptionsAccessor.Value.Formatters.Select(f => f.GetType().FullName).ToArray();
|
||||
return optionsAccessor.Value.Formatters.Select(f => f.GetType().FullName).ToArray();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
|
|
|
|||
Loading…
Reference in New Issue