Skip to content
This repository has been archived by the owner on Dec 14, 2018. It is now read-only.

TempData property attribute #5872

Merged
merged 11 commits into from
Mar 16, 2017
Merged

TempData property attribute #5872

merged 11 commits into from
Mar 16, 2017

Conversation

jbagga
Copy link
Contributor

@jbagga jbagga commented Mar 1, 2017

Work in progress for #5600

Support for Controllers added. Working on adding the filter for Pages (after this is merged)


namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
{
public class SaveTempDataPropertyFilter : ISaveTempDataCallback
/// <summary>
Copy link
Contributor

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;
Copy link
Contributor

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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readonly

Copy link
Member

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;
Copy link
Contributor

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?

Copy link
Member

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();
Copy link
Contributor

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?

Copy link
Member

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(
Copy link
Contributor

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>
Copy link
Contributor

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

Copy link
Member

@rynowak rynowak left a 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 PropertyHelpers 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();
Copy link
Member

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;
Copy link
Member

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();
Copy link
Member

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())
Copy link
Member

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());
Copy link
Member

@rynowak rynowak Mar 6, 2017

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
Copy link
Member

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.

Copy link
Contributor Author

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

@jbagga jbagga force-pushed the jbagga/TempData5600 branch from b8ded1f to 3d219d7 Compare March 8, 2017 02:11
@jbagga
Copy link
Contributor Author

jbagga commented Mar 8, 2017

Working on cleaning up and removing TempDataPropertyProvider (after adding a filter for Razor Pages)

@jbagga
Copy link
Contributor Author

jbagga commented Mar 8, 2017

@pranavkm @rynowak Need to decide how to add the filter for Razor Pages. Please take a look at the rest!

public string Prefix { get; set; }
private readonly ITempDataDictionaryFactory _factory;

internal IList<PropertyHelper> PropertyHelpers { get; set; }
Copy link
Member

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()
Copy link
Member

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);
}
Copy link
Member

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);
}
}
}
Copy link
Member

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.");
Copy link
Member

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)
Copy link
Member

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.

Copy link
Member

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?

Copy link
Member

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
Copy link
Member

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;
Copy link
Member

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)

Copy link
Member

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.

Copy link
Member

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-";
Copy link
Member

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).

Copy link
Member

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private const string

Copy link
Member

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);
Copy link
Member

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);
}
Copy link
Member

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.

@jbagga
Copy link
Contributor Author

jbagga commented Mar 10, 2017

@rynowak @pranavkm @kichalla Updated

@jbagga jbagga changed the title [Design] TempData property attribute TempData property attribute Mar 10, 2017
@jbagga jbagga requested review from kichalla and rynowak March 10, 2017 19:17
_factory = factory;
}

public string Prefix = "TempDataProperty-";
Copy link
Member

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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need not do ToArray

Copy link
Contributor

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.

Copy link
Member

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);
}

Copy link
Member

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
Copy link
Member

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
Copy link
Member

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; }
Copy link
Contributor

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.

Copy link
Contributor Author

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();
Copy link
Contributor

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)
Copy link
Contributor

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);
Copy link
Contributor

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; }
Copy link
Contributor

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);
}


Copy link
Contributor

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)
Copy link
Contributor

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)
Copy link
Contributor

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.
Copy link
Contributor

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-";
Copy link
Contributor

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();
Copy link
Member

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();
Copy link
Member

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;
Copy link
Member

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; } }
Copy link
Member

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.

Copy link
Contributor Author

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)))
Copy link
Member

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)))
Copy link
Member

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>
Copy link
Member

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 👍

@jbagga jbagga force-pushed the jbagga/TempData5600 branch from d1cfd27 to 05f91d4 Compare March 15, 2017 01:16
@jbagga
Copy link
Contributor Author

jbagga commented Mar 15, 2017

@rynowak @pranavkm Updated. Can you look at the exception messages? I am not sure how to get the FullName from the PropertyHelper.

@pranavkm
Copy link
Contributor

$"{PropertyInfo.DeclaringType.FullName}.{PropertyInfo.Name}". There's also TypeNameHelper which might help pretty printing the type name although I'm not sure we need that here.

@jbagga jbagga force-pushed the jbagga/TempData5600 branch from 05f91d4 to e512cf5 Compare March 15, 2017 19:07
@jbagga
Copy link
Contributor Author

jbagga commented Mar 15, 2017

@pranavkm Updated

property.GetMethod.IsPublic))
{
throw new InvalidOperationException(
Resources.FormatTempDataProperties_PublicGetterSetter(property.DeclaringType.FullName, property.Name, "TempDataAttribute"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nameof(TempDataAttribute)

Copy link
Member

@rynowak rynowak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: from me, make sure to get signoff from @kichalla and @pranavkm

{
public string Prefix { get; set; }
private readonly ITempDataDictionaryFactory _factory;
private const string Prefix = "TempDataProperty-";
Copy link
Contributor

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)
Copy link
Contributor

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());
Copy link
Contributor

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)
Copy link
Contributor

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
Copy link
Contributor

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>());
Copy link
Contributor

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>(() =>
Copy link
Contributor

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
Copy link
Contributor

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?

Copy link
Contributor

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.

Copy link
Contributor

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; }
Copy link
Contributor

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>(() =>
Copy link
Contributor

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));

@jbagga jbagga force-pushed the jbagga/TempData5600 branch from e512cf5 to 533ccd6 Compare March 16, 2017 20:47
@jbagga
Copy link
Contributor Author

jbagga commented Mar 16, 2017

@pranavkm Updated

var isReferenceTypeOrNullable = !propertyTypeInfo.IsValueType || Nullable.GetUnderlyingType(property.GetType()) != null;
if (value != null || isReferenceTypeOrNullable)
{
PropertyHelpers[i].SetValue(Subject, value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

property.SetValue

@jbagga jbagga force-pushed the jbagga/TempData5600 branch from 058899b to 43844ba Compare March 16, 2017 23:04
@jbagga jbagga merged commit 1197657 into dev Mar 16, 2017
@jbagga jbagga deleted the jbagga/TempData5600 branch March 17, 2017 00:37
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants