-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Conversation
ade635c
to
b8ded1f
Compare
|
||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal | ||
{ | ||
public class SaveTempDataPropertyFilter : ISaveTempDataCallback | ||
/// <summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't need docs
{ | ||
public string Prefix { get; set; } | ||
|
||
public object Subject { get; set; } | ||
|
||
public IDictionary<PropertyInfo, object> OriginalValues { get; set; } | ||
|
||
private TempDataPropertyProvider _propertyProvider = new TempDataPropertyProvider(); | ||
|
||
private readonly ITempDataDictionaryFactory _factory; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Readonly fields before ctor, properties go after.
{ | ||
public string Prefix { get; set; } | ||
|
||
public object Subject { get; set; } | ||
|
||
public IDictionary<PropertyInfo, object> OriginalValues { get; set; } | ||
|
||
private TempDataPropertyProvider _propertyProvider = new TempDataPropertyProvider(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
readonly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class was just temp code, we can get rid of it.
{ | ||
public class SaveTempDataPropertyFilterProvider : IFilterFactory | ||
{ | ||
public bool IsReusable => false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be reusable, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not, it's stateful
|
||
foreach (var controllerModel in context.Result.Controllers) | ||
{ | ||
var properties = controllerModel.ControllerType.GetProperties(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we be using controllerModel.ControllerProperties
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var properties = controllerModel.ControllerType.GetProperties(); | ||
foreach (var property in properties) | ||
{ | ||
if (property.CustomAttributes.Select( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look like a boolean condition? Maybe we can use property.CustomAttributes.OfType<TempDataAttribute>().Any()
@@ -18,6 +16,12 @@ public class TempDataPropertyProvider | |||
private ConcurrentDictionary<Type, IEnumerable<PropertyInfo>> _subjectProperties = | |||
new ConcurrentDictionary<Type, IEnumerable<PropertyInfo>>(); | |||
|
|||
/// <summary> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need docs for internal types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is shaping up.
The big piece of feedback here is that there should be 0 or 1 SaveTempDataPropertyFilter
per-controller. The property discovery should be based on PropertyHelper
(from common repo). The filter should store the PropertyHelper
s and avoid looking up the properties again.
{ | ||
public string Prefix { get; set; } | ||
|
||
public object Subject { get; set; } | ||
|
||
public IDictionary<PropertyInfo, object> OriginalValues { get; set; } | ||
|
||
private TempDataPropertyProvider _propertyProvider = new TempDataPropertyProvider(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class was just temp code, we can get rid of it.
{ | ||
public class SaveTempDataPropertyFilterProvider : IFilterFactory | ||
{ | ||
public bool IsReusable => false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not, it's stateful
|
||
foreach (var controllerModel in context.Result.Controllers) | ||
{ | ||
var properties = controllerModel.ControllerType.GetProperties(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
foreach (var property in properties) | ||
{ | ||
if (property.CustomAttributes.Select( | ||
a => a.AttributeType == typeof(TempDataAttribute)).FirstOrDefault()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use GetCustomAttribute(...) != null
if (property.CustomAttributes.Select( | ||
a => a.AttributeType == typeof(TempDataAttribute)).FirstOrDefault()) | ||
{ | ||
controllerModel.Filters.Add(new SaveTempDataPropertyFilterProvider()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not add a filter per-property.
Instead, add one filter to the controller, and make that filter remember all of the property helper instances that have [TempData]
|
||
namespace Microsoft.AspNetCore.Mvc.RazorPages | ||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal | ||
{ | ||
public class TempDataPropertyProvider |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's kill this class with fire. Move it into the filter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Follow up issue filed here: #5979
b8ded1f
to
3d219d7
Compare
Working on cleaning up and removing |
public string Prefix { get; set; } | ||
private readonly ITempDataDictionaryFactory _factory; | ||
|
||
internal IList<PropertyHelper> PropertyHelpers { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
properties after constructors
{ | ||
} | ||
|
||
private IEnumerable<PropertyInfo> GetSubjectProperties() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be done in the application model provider. The point is to avoid doing this every request.
if (value != null && property.PropertyType.IsAssignableFrom(value.GetType())) | ||
{ | ||
property.SetValue(Subject, value); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to check this here.
As far as null, you want to set null if the property can accept a null.
controllerModel.Filters.Add(provider); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great 👍
|
||
if (!(propertyHelper.Property.PropertyType.GetTypeInfo().IsPrimitive || propertyHelper.Property.PropertyType == typeof(string))) | ||
{ | ||
throw new InvalidOperationException("TempData properties must be declared as primitive types or string only."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be in resources
{ | ||
tempData[Prefix + property.Name] = newValue; | ||
} | ||
} | ||
} | ||
} | ||
|
||
public void OnActionExecuting(ActionExecutingContext context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question for @rynowak : Should we consider async api on ITempDataDictionary & ITempDataProvider at this point( (yeah there would be breaking changes)? Currently these apis are sync (for obvious reason that TempData access is sync in view of user experience), but if we provide this binding support to properties directly, then we could load the data in an async way. (For example, if SessionStateTempDataProvider is used, it could load a session in async way using ISession's LoadAsync). Also we would attempt to load temp data for all actions on a controller even though some of them might use it, which increases chances of thread blockage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We wouldn't add an async API to ITempDataDictionary
, it would go on the factory/provider. As far as doing this async goes, I'm not fully convinced that we need it. Separate issue maybe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. Filed here #5941
|
||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal | ||
{ | ||
public class SaveTempDataPropertyFilterProvider : IFilterFactory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SaveTempDataPropertyFilterProvider => SaveTempDataPropertyFilterFactory
{ | ||
internal IList<PropertyHelper> TempDataProperties { get; set; } | ||
|
||
public bool IsReusable => false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True? as one instance of the built (with property helpers) filter should be used for a controller. Also registration of SaveTempDataPropertyFilter
in MvcViewFeaturesMvcCoreBuilderExtensions.cs
looks incorrect (its currently singleton and should be transient)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is reusable applies to SaveTempDataPropertyFilter
which is stateful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point about reusable. Discussed with @rynowak about the registration, it should be transient
_factory = factory; | ||
} | ||
|
||
public string Prefix = "TempDataProperty-"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rynowak Wondering if we need this prefix...a scenario that I am thinking is for keep. If a value is bound to a tempdata property, it's as though its read and would be marked for deletion, but if a user chooses to keep it, then he might want to explicitly say TempData.Keep(nameof(OrderStatusMessage))
(where OrderStatusMessage is a TempData property).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not want to block this PR for this, but could you log an issue for this as its related to user experience.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private const string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have another issue for this already. It's been discussed 😆
// Assert 2 | ||
Assert.Equal(HttpStatusCode.OK, response.StatusCode); | ||
var body = await response.Content.ReadAsStringAsync(); | ||
Assert.Equal(expected, body); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to verify that the message was deleted from tempdata
Assert.Equal(HttpStatusCode.OK, response.StatusCode); | ||
var body = await response.Content.ReadAsStringAsync(); | ||
Assert.Equal(expected, body); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a test for keep scenario too.
88c2b68
to
d1cfd27
Compare
_factory = factory; | ||
} | ||
|
||
public string Prefix = "TempDataProperty-"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not want to block this PR for this, but could you log an issue for this as its related to user experience.
{ | ||
Subject = context.Controller; | ||
var tempData = _factory.GetTempData(context.HttpContext); | ||
var properties = PropertyHelpers.Select(p => p.Property).ToArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need not do ToArray
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's avoid the Linq call entirely. Also, this needs to throw if PropertyHelpers
is not initialized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need this at all actually, use the property helper to get/set the value.
{ | ||
property.SetValue(Subject, value); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove line
|
||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal | ||
{ | ||
public class SaveTempDataPropertyFilterFactory : IFilterFactory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change the name of this file too
Resources.FormatTempDataProperties_PrimitiveTypeOrString(property.Name)); | ||
} | ||
|
||
else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just return from here itself.
|
||
public object Subject { get; set; } | ||
|
||
public IDictionary<PropertyInfo, object> OriginalValues { get; set; } | ||
|
||
internal IList<PropertyHelper> PropertyHelpers { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't use internal
for any code that's not meant to be test-only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PropertyHelper
is an internal
class. I cannot make the IList<PropertyHelper>
public
because then the accessibility is inconsistent. If I set it to private
I cannot set them in the SaveTempDataPropertyFilterFactory
. Any suggestions to solve this?
{ | ||
Subject = context.Controller; | ||
var tempData = _factory.GetTempData(context.HttpContext); | ||
var properties = PropertyHelpers.Select(p => p.Property).ToArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's avoid the Linq call entirely. Also, this needs to throw if PropertyHelpers
is not initialized.
var properties = PropertyHelpers.Select(p => p.Property).ToArray(); | ||
OriginalValues = new Dictionary<PropertyInfo, object>(); | ||
|
||
foreach (var property in properties) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (var i = 0; i < PropertyHelpers.Count; i++)
{
var property = PropertyHelpers[i].Property;
...
}
|
||
if (value != null) | ||
{ | ||
property.SetValue(Subject, value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. Have to use the PropertyHelper
to call SetValue
.
{ | ||
public class SaveTempDataPropertyFilterFactory : IFilterFactory | ||
{ | ||
internal IList<PropertyHelper> TempDataProperties { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why internal?
Assert.Equal("TempData property Test is not declared as a primitive type or string.", exception.Message); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove extra line. Also needs tests to verify that it initializes the filter with the right PropertyHelpers
[HttpPost] | ||
public IActionResult CreateForView(Person person) | ||
{ | ||
if (ModelState.IsValid) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure you need these. We aren't testing ModelBinding here (are we)?
return $"{Message} for person {person.FullName} with id {person.id}."; | ||
} | ||
|
||
public void CreateNoRedirect(Person person) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just use an OkResult
. void
returning actions are not very typical.
@@ -0,0 +1,2 @@ | |||
@model BasicWebSite.Models.Person | |||
@ViewData["Message"] for person @Model.FullName with id @Model.id. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a new line at the end of the file.
_factory = factory; | ||
} | ||
|
||
public string Prefix = "TempDataProperty-"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private const string
{ | ||
Subject = context.Controller; | ||
var tempData = _factory.GetTempData(context.HttpContext); | ||
var properties = PropertyHelpers.Select(p => p.Property).ToArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need this at all actually, use the property helper to get/set the value.
|
||
OriginalValues[property] = value; | ||
|
||
var propertyInfo = property.PropertyType.GetTypeInfo(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a PropertyInfo
, it's the TypeInfo
of the property.
using Microsoft.AspNetCore.Mvc.Filters; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Internal; | ||
using System.Collections.Generic; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sort
public class TempDataApplicationModelProvider : IApplicationModelProvider | ||
{ | ||
/// <inheritdoc /> | ||
public int Order { get { return -1000 + 10; } } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leave a comment here explaining why this value is significant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This value is the same as other ApplicationModelProviders like AuthorizationApplicationModelProvider
and CorsApplicationModelProvider
. Is that correct?
Resources.FormatTempDataProperties_PublicGetterSetter(property.Name)); | ||
} | ||
|
||
if (!(property.PropertyType.GetTypeInfo().IsPrimitive || property.PropertyType == typeof(string))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is ok for now. There's been lots of confusion about this in the past.
Resources.FormatTempDataProperties_PublicGetterSetter(property.Name)); | ||
} | ||
|
||
if (!(property.PropertyType.GetTypeInfo().IsPrimitive || property.PropertyType == typeof(string))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pranavkm - please start an email thread or open an issue about this.
<value>TempData property {0} is not declared as a primitive type or string.</value> | ||
</data> | ||
<data name="TempDataProperties_PublicGetterSetter" xml:space="preserve"> | ||
<value>TempData property {0} does not have a public getter or setter.</value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be more friendly to read, like:
The {0} property with {1} is invalid. A property using {1} must have a public getter and setter.
Never hardcode the names of 'code things' like TempData
in a resource. It's better to make it a parameter and pass in the name.
Make sure that the property name that's reported here includes the full type name as well. We want to make sure that you can find the issue 👍
d1cfd27
to
05f91d4
Compare
$"{PropertyInfo.DeclaringType.FullName}.{PropertyInfo.Name}". There's also |
05f91d4
to
e512cf5
Compare
@pranavkm Updated |
property.GetMethod.IsPublic)) | ||
{ | ||
throw new InvalidOperationException( | ||
Resources.FormatTempDataProperties_PublicGetterSetter(property.DeclaringType.FullName, property.Name, "TempDataAttribute")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nameof(TempDataAttribute)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ | ||
public string Prefix { get; set; } | ||
private readonly ITempDataDictionaryFactory _factory; | ||
private const string Prefix = "TempDataProperty-"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typical field order we use in most places in our code: public const
, non-public const
, public static readonly
, 'private static readonly,
readonly`, and finally non-readonly fields.
|
||
var propertyTypeInfo = property.PropertyType.GetTypeInfo(); | ||
|
||
if (value != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var isReferenceTypeOrNullable = !propertyTypeInfo.IsValueType || Nullable.GetUnderlyingType(ModelType) != null;
if (value != null || isReferenceTypeOrNullable)
{
property.SetValue(...);
}
You can remove the generic check once you do this.
foreach (var controllerModel in context.Result.Controllers) | ||
{ | ||
SaveTempDataPropertyFilterFactory factory = null; | ||
var propertyHelpers = PropertyHelper.GetVisibleProperties(controllerModel.ControllerType.AsType()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you make this PropertyHelper.GetVisibleProperties(type: controllerModel.ControllerType.AsType())
. Should eliminate accidental use of the object
overload
var propertyHelpers = PropertyHelper.GetVisibleProperties(controllerModel.ControllerType.AsType()); | ||
for (var i = 0; i < propertyHelpers.Length; i++) | ||
{ | ||
if (propertyHelpers[i].Property.GetCustomAttribute<TempDataAttribute>() != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var propertyHelper = propertyHelpers[i];
if (propertyHelper.Property.IsDefined(typeof(TempDataAttribute))
...
@@ -3,7 +3,7 @@ | |||
|
|||
using System; | |||
|
|||
namespace Microsoft.AspNetCore.Mvc.Rendering | |||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures | |||
{ | |||
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] | |||
public sealed class TempDataAttribute : Attribute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs
Assert.NotNull(saveTempDataPropertyFilterFactory); | ||
var tempDataPropertyHelper = Assert.Single(saveTempDataPropertyFilterFactory.TempDataProperties); | ||
Assert.Equal("Test2", tempDataPropertyHelper.Name); | ||
Assert.NotNull(tempDataPropertyHelper.Property.GetCustomAttribute<TempDataAttribute>()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could simply assert it's the exact property instead of verifying two pieces of information about it:
var expected = typeof(TestController_OneTempDataProperty).GetProperty(nameof(TestController_OneTempDataProperty.Test2);
...
Assert.Same(expected, tempDataPropertyHelper.Property);
defaultProvider.OnProvidersExecuting(context); | ||
|
||
// Act & Assert | ||
var exception = Assert.Throws<InvalidOperationException>(() => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var exception = Assert.Throws<InvalidOperationException>(() => provider.OnProvidersExecuting(context));
public string Test { get; private set; } | ||
} | ||
|
||
public class TestController_NonPrimitiveType : Controller |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a scenario where some of the properties are valid and the others aren't allowed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you include collection of primitives as a negative case? Cookie and session temp data provider allow IList<string>
for example, but the property does not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, should we print all possible errors when doing this? @rynowak is there any other equivalent in application model where the error includes all issues?
public string Test { get; set; } | ||
|
||
[TempData] | ||
public string Test2 { get; set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add non-string properties to this one? For instance an int
?
}; | ||
|
||
// Act & Assert | ||
var exception = Assert.Throws<InvalidOperationException>(() => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var exception = Assert.Throws<InvalidOperationException>(() => provider.LoadAndTrackChanges(controller, controller.TempData));
e512cf5
to
533ccd6
Compare
@pranavkm Updated |
var isReferenceTypeOrNullable = !propertyTypeInfo.IsValueType || Nullable.GetUnderlyingType(property.GetType()) != null; | ||
if (value != null || isReferenceTypeOrNullable) | ||
{ | ||
PropertyHelpers[i].SetValue(Subject, value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
property.SetValue
058899b
to
43844ba
Compare
Work in progress for #5600
Support for Controllers added. Working on adding the filter for Pages (after this is merged)