Microsoft.Owin.Security.AuthenticationTicket 使用 RedisSessionStateProvider 时出现 SerializationException
Microsoft.Owin.Security.AuthenticationTicket SerializationException when using RedisSessionStateProvider
我在我的应用程序中使用 Owin OpenIdConnectAuthentication 模块,并试图将我的会话状态移动到 Redis。我为此使用 Microsoft.Web.Redis.RedisSessionStateProvider
。当我更新 web.config 以添加 RedisSessionStateProvider
时,我开始收到此错误:
Type 'Microsoft.Owin.Security.AuthenticationTicket' in Assembly 'Microsoft.Owin.Security, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable.
堆栈跟踪
[SerializationException: Type 'Microsoft.Owin.Security.AuthenticationTicket' in Assembly 'Microsoft.Owin.Security, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable.]
System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) +10951483
System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) +230
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() +121
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) +182
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) +51
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) +540
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) +131
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph) +12
Microsoft.Web.Redis.RedisUtility.GetBytesFromObject(Object data) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\Shared\RedisUtility.cs:65
Microsoft.Web.Redis.RedisUtility.AppendUpdatedOrNewItemsInList(ChangeTrackingSessionStateItemCollection sessionItems, List`1 list) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\Shared\RedisUtility.cs:37
Microsoft.Web.Redis.RedisConnectionWrapper.TryUpdateIfLockIdMatchPrepare(Object lockId, ISessionStateItemCollection data, Int32 sessionTimeout, String[]& keyArgs, Object[]& valueArgs) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\RedisSessionStateProvider\RedisConnectionWrapper.cs:323
Microsoft.Web.Redis.RedisConnectionWrapper.TryUpdateAndReleaseLockIfLockIdMatch(Object lockId, ISessionStateItemCollection data, Int32 sessionTimeout) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\RedisSessionStateProvider\RedisConnectionWrapper.cs:350
Microsoft.Web.Redis.RedisSessionStateProvider.SetAndReleaseItemExclusive(HttpContext context, String id, SessionStateStoreData item, Object lockId, Boolean newItem) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\RedisSessionStateProvider\RedisSessionStateProvider.cs:408
System.Web.SessionState.SessionStateModule.OnReleaseState(Object source, EventArgs eventArgs) +565
System.Web.SessionState.SessionStateModule.OnEndRequest(Object source, EventArgs eventArgs) +139
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69
我是不是在某处遗漏了一些配置?我能找到的关于序列化 AuthenticationTicket
对象的所有文档都是针对 OAuth server 实现的。
我们使用的是 Katana 的 AspNetAuthSessionStore sample。显然,此示例仅适用于 InProc 会话状态。我们进行了以下更改以通过手动序列化 AuthenticationTicket
:
来解决此问题
public Task<string> StoreAsync(AuthenticationTicket ticket)
{
string key = Guid.NewGuid().ToString();
HttpContext httpContext = HttpContext.Current;
CheckSessionAvailable(httpContext);
//httpContext.Session[key + ".Ticket"] = ticket; // Remove
var ticketSerializer = new TicketSerializer(); // Add
var ticketBytes = ticketSerializer.Serialize(ticket); // Add
httpContext.Session[key + ".Ticket"] = ticketBytes; // Add
return Task.FromResult(key);
}
我在我的应用程序中使用 Owin OpenIdConnectAuthentication 模块,并试图将我的会话状态移动到 Redis。我为此使用 Microsoft.Web.Redis.RedisSessionStateProvider
。当我更新 web.config 以添加 RedisSessionStateProvider
时,我开始收到此错误:
Type 'Microsoft.Owin.Security.AuthenticationTicket' in Assembly 'Microsoft.Owin.Security, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable.
堆栈跟踪
[SerializationException: Type 'Microsoft.Owin.Security.AuthenticationTicket' in Assembly 'Microsoft.Owin.Security, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable.]
System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) +10951483
System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) +230
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() +121
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) +182
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) +51
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) +540
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) +131
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph) +12
Microsoft.Web.Redis.RedisUtility.GetBytesFromObject(Object data) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\Shared\RedisUtility.cs:65
Microsoft.Web.Redis.RedisUtility.AppendUpdatedOrNewItemsInList(ChangeTrackingSessionStateItemCollection sessionItems, List`1 list) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\Shared\RedisUtility.cs:37
Microsoft.Web.Redis.RedisConnectionWrapper.TryUpdateIfLockIdMatchPrepare(Object lockId, ISessionStateItemCollection data, Int32 sessionTimeout, String[]& keyArgs, Object[]& valueArgs) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\RedisSessionStateProvider\RedisConnectionWrapper.cs:323
Microsoft.Web.Redis.RedisConnectionWrapper.TryUpdateAndReleaseLockIfLockIdMatch(Object lockId, ISessionStateItemCollection data, Int32 sessionTimeout) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\RedisSessionStateProvider\RedisConnectionWrapper.cs:350
Microsoft.Web.Redis.RedisSessionStateProvider.SetAndReleaseItemExclusive(HttpContext context, String id, SessionStateStoreData item, Object lockId, Boolean newItem) in c:\TeamCity\buildAgent\work\f55792526e6d9089\src\RedisSessionStateProvider\RedisSessionStateProvider.cs:408
System.Web.SessionState.SessionStateModule.OnReleaseState(Object source, EventArgs eventArgs) +565
System.Web.SessionState.SessionStateModule.OnEndRequest(Object source, EventArgs eventArgs) +139
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69
我是不是在某处遗漏了一些配置?我能找到的关于序列化 AuthenticationTicket
对象的所有文档都是针对 OAuth server 实现的。
我们使用的是 Katana 的 AspNetAuthSessionStore sample。显然,此示例仅适用于 InProc 会话状态。我们进行了以下更改以通过手动序列化 AuthenticationTicket
:
public Task<string> StoreAsync(AuthenticationTicket ticket)
{
string key = Guid.NewGuid().ToString();
HttpContext httpContext = HttpContext.Current;
CheckSessionAvailable(httpContext);
//httpContext.Session[key + ".Ticket"] = ticket; // Remove
var ticketSerializer = new TicketSerializer(); // Add
var ticketBytes = ticketSerializer.Serialize(ticket); // Add
httpContext.Session[key + ".Ticket"] = ticketBytes; // Add
return Task.FromResult(key);
}