Implementing a Custom Identity and IPrincipal in MVC
Asked Answered
G

3

19

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.

Godmother answered 10/12, 2009 at 21:6 Comment(1)
Re: the up vote...Are you also seeing a similar issue?Godmother
G
16

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"

Godmother answered 11/12, 2009 at 21:42 Comment(4)
this feature is bs... its been around since 2006 and still affecting me with my asp.net mvc-3 application.Frankenstein
This solved my problem. The same thing goes for IPrincipal as well.Paviour
why are you created a new GenericIdentity instead of a CustomIdentity in your DeSerialization code? => `GenericIdentity gIdent = new GenericIdentity(...)' ??Selestina
Just wanted to note that there is a difference between System.ISerializable and System.Runtime.Serialization.ISerializable. I struggled with the first for a while before realizing the second (System.Runtime.Serialization.ISerializable) was the one I needed.Manumit
P
11

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;
            }
        }
    }
Particularize answered 10/12, 2010 at 22:30 Comment(0)
T
4

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.

Teraterai answered 9/7, 2010 at 15:36 Comment(1)
#6503880 there is more on marshalbyrefobjectPaulsen

© 2022 - 2024 — McMap. All rights reserved.