Monday, December 22, 2008

"type is not resolved for member" for Csla Security IPrincipal, IIdentity

According to an article I found, when using the ASP.NET Development Server (VS Host or Cassini): ("Objects placed on the Thread object, such as the CurrentPrincipal, must be serializable and the assembly must be available to all AppDomains; even the primary AppDomain that isn’t running as part of your web site!"

Here is the article from Rockford Lhotka on the problem:
http://www.lhotka.net/WeBlog/CommentView,guid,cfcaf6c4-63cf-4cf1-8361-ed3db07496a4.aspx

To solve the problem, implement your own serialization for your IPrincipal and IIdentity objects:


//Identity class. Note: Inherits ISerializable

#region ISerializable Members

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
//State will be CrossAppDomain for serialization induced by WebDev.WebServer
if(context.State.Equals(StreamingContextStates.CrossAppDomain))
{
var generic = new GenericIdentity(this.Name, this.AuthenticationType);

info.SetType(generic.GetType());

var serializableMembers = FormatterServices.GetSerializableMembers(generic.GetType());
var serializableValues = FormatterServices.GetObjectData(generic, serializableMembers);

for(int i = 0; i < serializableMembers.Length; i++)
info.AddValue(serializableMembers[i].Name, serializableValues[i]);
}
else
throw new InvalidOperationException("Serialization not supported");
}

#endregion

//Principal class. Note: Inherits ISerializable
#region ISerializable Members

public void GetObjectData(SerializationInfo info, StreamingContext context)
{
//State will be CrossAppDomain for serialization induced by WebDev.WebServer
if (context.State.Equals(StreamingContextStates.CrossAppDomain))
{
var identity = (MyIdentity)this.Identity;

var generic = new GenericPrincipal(identity, identity.Roles.ToArray()); ;

info.SetType(generic.GetType());

var serializableMembers = FormatterServices.GetSerializableMembers(generic.GetType());
var serializableValues = FormatterServices.GetObjectData(generic, serializableMembers);

for (int i = 0; i < serializableMembers.Length; i++)
info.AddValue(serializableMembers[i].Name, serializableValues[i]);
}
else
{
throw new InvalidOperationException("Serialization not supported");
}
}

#endregion



Things to do to make this work:
1. ISerializable on both IPrincipal, IIdentity
2. Added property to expose roles on identity object for IPrincipal serialization

This is a minor problem, and the fix above works like a charm. The hardest part was finding the solution. Thanks to Rocky...

Resources:
Update on my struggles with the ASP.NET Development Server
Type is not resolved for member ... Having problems enabling debugging

No comments: