I have a basic MVC 2 beta app where I am trying to implement a custom Identity and Principal classes.
I have created my classes that implement the IIdentity and IPrincipal interfaces, instantiated them and then assigned the CustomPrincipal object to my Context.User in Application_AuthenticateRequest of the Global.asax.
This all succeeds and the objects look good. When I begin to render the Views the pages are now failing. The first failure is in the default LogoOnUserControl view on the following line of code:
[ <%= Html.ActionLink("Log Off", "LogOff", "Account") %> ]
If I pull this out it then fails on a different "Html.ActionLink" line of code.
The error I receive is:
An exception of type
'System.Runtime.Serialization.SerializationException'
occurred in WebDev.WebHost40.dll but
was not handled in user code
Additional information: Type is not
resolved for member
'Model.Entities.UserIdentity,Model,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null'.
Is there some additional properties that I need to implement in my Identity in order to use a custom Identity in MVC? I tried to implement [Serializable()] in the Identity class but it didn't seem to have an impact.
UPDATE:
I've tried 3-4 alternate ways of implemented this but still fails with the same error. If I use GenericIdentity/GenericPrincipal classes directly it does not error.
GenericIdentity ident = new GenericIdentity("jzxcvcx");
GenericPrincipal princ = new GenericPrincipal(ident, null);
Context.User = princ;
But this gets me nowhere since I am trying to use the CustomIdentity to hold a couple of properties. If I implement the IIdentity/IPrincipal interfaces or inherit GenericIdentity/GenericPrincipal for my CustomIdentity/CustomPrincipal it fails with the original error above.
I figured this one out with a little help from the web :) The trick is that you have to implement the ISerializable interface in your class that implements IIdentity. I hope this helps save someone else some time :)
Class declaration:
[Serializable]
public class ForumUserIdentity : IIdentity, ISerializable
Implementation for ISerializable:
#region ISerializable Members
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (context.State == StreamingContextStates.CrossAppDomain)
{
GenericIdentity gIdent = new GenericIdentity(this.Name, this.AuthenticationType);
info.SetType(gIdent.GetType());
System.Reflection.MemberInfo[] serializableMembers;
object[] serializableValues;
serializableMembers = FormatterServices.GetSerializableMembers(gIdent.GetType());
serializableValues = FormatterServices.GetObjectData(gIdent, serializableMembers);
for (int i = 0; i < serializableMembers.Length; i++)
{
info.AddValue(serializableMembers[i].Name, serializableValues[i]);
}
}
else
{
throw new InvalidOperationException("Serialization not supported");
}
}
#endregion
Here is the link to the article that has more detail on the "Feature"
I had the same problem. I solved it by moving my principal creating from MvcApplication_AuthenticateRequest to MvcApplication_PostAuthenticateRequest.
I dunno why/how, but it solved the problem :)
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
string encTicket = authCookie.Value;
if (!String.IsNullOrEmpty(encTicket))
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encTicket);
BiamedIdentity id = new BiamedIdentity(ticket);
GenericPrincipal prin = new GenericPrincipal(id, null);
HttpContext.Current.User = prin;
}
}
}
With me it seems to work when I inherit my Identity class from MarshalByRefObject
.
Also note: when using Linq-to-Sql there was no problem. I switched to Entity-Framework and bang, I got the above message.