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

Commit

Permalink
[Fixes #3068] TempData fails silently without sessions middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
kichalla committed Oct 1, 2015
1 parent 2028351 commit 06e388e
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,8 @@ public virtual IDictionary<string, object> LoadTempData(HttpContext context)
throw new ArgumentNullException(nameof(context));
}

if (!IsSessionEnabled(context))
{
// Session middleware is not enabled. No-op
return null;
}

// Accessing Session property will throw if the session middleware is not enabled.
var session = context.Session;
if (session == null)
{
return null;
}

var tempDataDictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
byte[] value;
Expand Down Expand Up @@ -162,6 +153,9 @@ public virtual void SaveTempData(HttpContext context, IDictionary<string, object
throw new ArgumentNullException(nameof(context));
}

// Accessing Session property will throw if the session middleware is not enabled.
var session = context.Session;

var hasValues = (values != null && values.Count > 0);
if (hasValues)
{
Expand All @@ -171,9 +165,6 @@ public virtual void SaveTempData(HttpContext context, IDictionary<string, object
EnsureObjectCanBeSerialized(item);
}

// Accessing Session property will throw if the session middleware is not enabled.
var session = context.Session;

using (var memoryStream = new MemoryStream())
{
using (var writer = new BsonWriter(memoryStream))
Expand All @@ -183,18 +174,12 @@ public virtual void SaveTempData(HttpContext context, IDictionary<string, object
}
}
}
else if (IsSessionEnabled(context))
else
{
var session = context.Session;
session.Remove(TempDataSessionStateKey);
}
}

private static bool IsSessionEnabled(HttpContext context)
{
return context.Features.Get<ISessionFeature>() != null;
}

internal void EnsureObjectCanBeSerialized(object item)
{
var itemType = item.GetType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,13 @@ public object this[string key]
/// <inheritdoc />
public void Keep()
{
Load();
// if the data is not loaded, we can assume none of it has been read
// and so silently return.
if (!_loaded)
{
return;
}

_retainedKeys.Clear();
_retainedKeys.UnionWith(_data.Keys);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,68 +16,44 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
public class SessionStateTempDataProviderTest
{
[Fact]
public void Load_NullSession_ReturnsEmptyDictionary()
public void Load_ThrowsException_WhenSessionIsNotEnabled()
{
// Arrange
var testProvider = new SessionStateTempDataProvider();

// Act
var tempDataDictionary = testProvider.LoadTempData(
GetHttpContext(session: null, sessionEnabled: true));

// Assert
Assert.Null(tempDataDictionary);
}

[Fact]
public void Load_NonNullSession_NoSessionData_ReturnsEmptyDictionary()
{
// Arrange
var testProvider = new SessionStateTempDataProvider();

// Act
var tempDataDictionary = testProvider.LoadTempData(
GetHttpContext(Mock.Of<ISession>()));

// Assert
Assert.Empty(tempDataDictionary);
// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
{
testProvider.LoadTempData(GetHttpContext(sessionEnabled: false));
});
}

[Fact]
public void Save_NullSession_NullDictionary_DoesNotThrow()
public void Save_ThrowsException_WhenSessionIsNotEnabled()
{
// Arrange
var testProvider = new SessionStateTempDataProvider();
var values = new Dictionary<string, object>();
values.Add("key1", "value1");

// Act & Assert (does not throw)
testProvider.SaveTempData(GetHttpContext(session: null, sessionEnabled: false), null);
// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
{
testProvider.SaveTempData(GetHttpContext(sessionEnabled: false), values);
});
}

[Fact]
public void Save_NullSession_EmptyDictionary_DoesNotThrow()
public void Load_ReturnsEmptyDictionary_WhenNoSessionDataIsAvailable()
{
// Arrange
var testProvider = new SessionStateTempDataProvider();

// Act & Assert (does not throw)
testProvider.SaveTempData(
GetHttpContext(session: null, sessionEnabled: false), new Dictionary<string, object>());
}

[Fact]
public void Save_NullSession_NonEmptyDictionary_Throws()
{
// Arrange
var testProvider = new SessionStateTempDataProvider();
// Act
var tempDataDictionary = testProvider.LoadTempData(GetHttpContext());

// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
{
testProvider.SaveTempData(
GetHttpContext(session: null, sessionEnabled: false),
new Dictionary<string, object> { { "foo", "bar" } }
);
});
// Assert
Assert.Empty(tempDataDictionary);
}

public static TheoryData<object, Type> InvalidTypes
Expand All @@ -97,7 +73,7 @@ public static TheoryData<object, Type> InvalidTypes

[Theory]
[MemberData(nameof(InvalidTypes))]
public void EnsureObjectCanBeSerialized_InvalidType_Throws(object value, Type type)
public void EnsureObjectCanBeSerialized_ThrowsException_OnInvalidType(object value, Type type)
{
// Arrange
var testProvider = new SessionStateTempDataProvider();
Expand All @@ -107,7 +83,8 @@ public void EnsureObjectCanBeSerialized_InvalidType_Throws(object value, Type ty
{
testProvider.EnsureObjectCanBeSerialized(value);
});
Assert.Equal($"The '{typeof(SessionStateTempDataProvider).FullName}' cannot serialize an object of type '{type}' to session state.",
Assert.Equal($"The '{typeof(SessionStateTempDataProvider).FullName}' cannot serialize " +
$"an object of type '{type}' to session state.",
exception.Message);
}

Expand All @@ -127,7 +104,7 @@ public static TheoryData<object, Type> InvalidDictionaryTypes

[Theory]
[MemberData(nameof(InvalidDictionaryTypes))]
public void EnsureObjectCanBeSerialized_InvalidDictionaryType_Throws(object value, Type type)
public void EnsureObjectCanBeSerialized_ThrowsException_OnInvalidDictionaryType(object value, Type type)
{
// Arrange
var testProvider = new SessionStateTempDataProvider();
Expand All @@ -137,7 +114,8 @@ public void EnsureObjectCanBeSerialized_InvalidDictionaryType_Throws(object valu
{
testProvider.EnsureObjectCanBeSerialized(value);
});
Assert.Equal($"The '{typeof(SessionStateTempDataProvider).FullName}' cannot serialize a dictionary with a key of type '{type}' to session state.",
Assert.Equal($"The '{typeof(SessionStateTempDataProvider).FullName}' cannot serialize a dictionary " +
$"with a key of type '{type}' to session state.",
exception.Message);
}

Expand All @@ -163,7 +141,7 @@ public static TheoryData<object> ValidTypes

[Theory]
[MemberData(nameof(ValidTypes))]
public void EnsureObjectCanBeSerialized_ValidType_DoesNotThrow(object value)
public void EnsureObjectCanBeSerialized_DoesNotThrow_OnValidType(object value)
{
// Arrange
var testProvider = new SessionStateTempDataProvider();
Expand All @@ -181,7 +159,7 @@ public void SaveAndLoad_StringCanBeStoredAndLoaded()
{
{ "string", "value" }
};
var context = GetHttpContext(new TestSession(), true);
var context = GetHttpContext();

// Act
testProvider.SaveTempData(context, input);
Expand All @@ -201,7 +179,7 @@ public void SaveAndLoad_IntCanBeStoredAndLoaded()
{
{ "int", 10 }
};
var context = GetHttpContext(new TestSession(), true);
var context = GetHttpContext();

// Act
testProvider.SaveTempData(context, input);
Expand All @@ -223,7 +201,7 @@ public void SaveAndLoad_BoolCanBeStoredAndLoaded(bool value)
{
{ "bool", value }
};
var context = GetHttpContext(new TestSession(), true);
var context = GetHttpContext();

// Act
testProvider.SaveTempData(context, input);
Expand All @@ -244,7 +222,7 @@ public void SaveAndLoad_DateTimeCanBeStoredAndLoaded()
{
{ "DateTime", inputDatetime }
};
var context = GetHttpContext(new TestSession(), true);
var context = GetHttpContext();

// Act
testProvider.SaveTempData(context, input);
Expand All @@ -265,7 +243,7 @@ public void SaveAndLoad_GuidCanBeStoredAndLoaded()
{
{ "Guid", inputGuid }
};
var context = GetHttpContext(new TestSession(), true);
var context = GetHttpContext();

// Act
testProvider.SaveTempData(context, input);
Expand All @@ -285,7 +263,7 @@ public void SaveAndLoad_ListCanBeStoredAndLoaded()
{
{ "List`string", new List<string> { "one", "two" } }
};
var context = GetHttpContext(new TestSession(), true);
var context = GetHttpContext();

// Act
testProvider.SaveTempData(context, input);
Expand All @@ -311,7 +289,7 @@ public void SaveAndLoad_DictionaryCanBeStoredAndLoaded()
{
{ "Dictionary", inputDictionary }
};
var context = GetHttpContext(new TestSession(), true);
var context = GetHttpContext();

// Act
testProvider.SaveTempData(context, input);
Expand All @@ -331,7 +309,7 @@ public void SaveAndLoad_EmptyDictionary_RoundTripsAsNull()
{
{ "EmptyDictionary", new Dictionary<string, int>() }
};
var context = GetHttpContext(new TestSession(), true);
var context = GetHttpContext();

// Act
testProvider.SaveTempData(context, input);
Expand All @@ -347,12 +325,12 @@ private class TestItem
public int DummyInt { get; set; }
}

private HttpContext GetHttpContext(ISession session, bool sessionEnabled = true)
private HttpContext GetHttpContext(bool sessionEnabled = true)
{
var httpContext = new DefaultHttpContext();
if(sessionEnabled)
if (sessionEnabled)
{
httpContext.Features.Set<ISessionFeature>(new SessionFeature() { Session = session });
httpContext.Features.Set<ISessionFeature>(new SessionFeature() { Session = new TestSession() });
}
return httpContext;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Internal;
using Moq;
using Xunit;

namespace Microsoft.AspNet.Mvc.ViewFeatures
{
public class TempDataDictionaryTest
{
[Fact]
public void ThrowscdException_OnSettingValue_AndWhenSessionIsNotEnabled()
{
// Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new SessionStateTempDataProvider());

// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
{
tempData["key1"] = "value1";
});
}

[Fact]
public void Keep_DoesNotThrowException_WhenDataIsNotLoaded()
{
// Arrange
var tempData = new TempDataDictionary(GetHttpContextAccessor(), new SessionStateTempDataProvider());

// Act & Assert
tempData.Keep();
}

[Fact]
public void TempData_Load_CreatesEmptyDictionaryIfProviderReturnsNull()
{
Expand Down Expand Up @@ -214,10 +239,7 @@ public void SaveTempData(HttpContext context, IDictionary<string, object> values

private static IHttpContextAccessor GetHttpContextAccessor()
{
var httpContext = new Mock<HttpContext>();
var httpContextAccessor = new Mock<IHttpContextAccessor>();
httpContextAccessor.Setup(h => h.HttpContext).Returns(httpContext.Object);
return httpContextAccessor.Object;
return new HttpContextAccessor() { HttpContext = new DefaultHttpContext() };
}
}
}

0 comments on commit 06e388e

Please sign in to comment.