Home > MOSS 2007 > Today’s Nuances

Today’s Nuances

January 11th, 2008 Leave a comment Go to comments

Today I was developing a custom forms based authentication provider against CRM 3.0 when I got three exceptions that led to an interesting outcome.

OS: Windows 2003 Enterprise Edition x64
IDE: Visual Studio 2008 RTM
Configuration: Default Zone (http://toronto1) with NTLM, Internet Zone (http://toronto1:26415) with FBA
Debugging Mode : Locally
Exception1: System.Threading.ThreadAbortException.
Exception2: Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack.
Exception3: Mixed mode debugging is not supported on Windows 64-bit platforms .

Before I get into how I got the exceptions, let me elaborate a bit on how I was led to all this. After developing the authentication provider, I created a log in web part that authenticates the users against CRM database (using my custom auth provider) and add them to the Visitors group upon thier successful login plus some other custom actions which is beyond the scope of this post. In the CreateChildControls() event , I created an standard login control using the following code:

1: loginCtrl = new Login();
2: loginCtrl.UserNameLabelText = UserNameLabelText;
.
.
.
6: loginCtrl.LoggedIn += new EventHandler(loginCtrl_LoggedIn);
7: Controls.Add(loginCtrl);

Log in control exposes a helpful event called LoggedIn (Line 6 above) that gives you the ability to take custom actions after the user is successfully authenticated. I went ahead and coded it as follow:

1. void loginCtrl_LoggedIn(object sender, EventArgs e)
2. {
3. //Get the user from Membership provider
4. MembershipUser user = Membership.GetUser(((TextBox)loginCtrl.FindControl(“UserName”)).Text);
5. if (user != null)
6. {
7. SPWeb web = SPContext.Current.Web;
8. SPGroup vGroup = web.AssociatedVisitorGroup;
9. //Add user to visitor group and other custom actions are removed for code brevity
10. Page.Response.Redirect(Page.Request.Url.ToString());
11. }
12. }

While I was debugging the code (for Internet zone at http://toronto1:26415 ) and right on the line 7 , I got Exception1 and Exception2 thrown:

After the execution of code in the line 7, I checked the ULS log and found “Thread was being aborted” exception there too. I have seen “System.Threading.ThreadAbortException” in other contexts (As you can see later in this post) , but never for SPWeb object (Web.AssociatedGroups). Second exception (Unable to evaluate expression because….) which is the result of first exception makes sense though. If the thread is currently stopped somewhere outside the generated code by IL , then the rest of properties fail to be evaluated, so I have to find out why the current thread is being halted. Earlier in my web part , I had some calls into unmanaged code (Not included in this post) and the fact that many SharePoint objects (such as SPWeb) are actually thin managed wrapper over the unmanaged code made me think to debug my code in Mixed mode (Native,Managed) with the hope to nail down the issue by looking at the all of the current call stack. Default debug settings for attaching to the worker process is set to automatically determine the type of code to debug which is T-SQL code and Managed code as shown below.

I switched to mixed debug mode to target debugging for Managed and Native code:

Then I got this error:

After some research , I was pointed to a MSDN article here .Apparently, It is well known that mixed-mode debugging is not supported when running in 64-bit mode. Dead end path, so let’s move on! I decided to debug the code again by logging with the same credential as application pool. Guess what? I didn’t get these two exceptions when I logged in to the site with application pool identity and debugged my code. It turned out that these exceptions were hiding the true exception (“Access Denied”) and I was not paying attention to this at all. My bad…….I ran the code with elevated privilege and everything came back to the normal life:

  1. //Get the user
  2. MembershipUser user = Membership.GetUser(((TextBox)loginCtrl.FindControl(“UserName”)).Text);
  3. if (user != null)
  4. {
  5.   SPWeb webInUserContext = SPContext.Current.Web;
  6.   SPSite SiteInUserContext = SPContext.Current.Site;
  7.   Guid webGuid = webInUserContext.ID;
  8.   Guid siteGuid = SiteInUserContext.ID;
  9.   SPSecurity.RunWithElevatedPrivileges(delegate()
  10.    {
  11.    // Get the site in impersonated context
  12.   using (SPSite site = new SPSite(siteGuid))
  13.     {
  14.     // Get the web in the impersonated context
  15.     SPWeb web = site.OpenWeb(webGuid);
  16.     try
  17.      {
  18.        SPGroup vGroup = web.AssociatedVisitorGroup;
  19.        // Extra code is removed for brevity
  20.        Page.Response.Redirect(Page.Request.Url.ToString());
  21.      }
  22.      catch (Exception exc)
  23.     {
  24.      TraceProvider.WriteTrace(“bluh bluh bluh”);
  25.     }
  26.     finally
  27.     {
  28.        if (web != null) web.Dispose();
  29.     }
  30.    }
  31.   });
  32. }

wait a second!!! Exception 2 occurs again when I step through the code at the Response.Redirect (at line 20). No worries. I knew my way out this time 🙂

This was exactly the same thing was happening above. Current thread gets aborted and you get this error message. You have three options here (depending on your code ):

  1. You can use a try-catch statement to catch this exception (as I did above)
  2. Sometimes If you move the redirect statement outside the block it works fine.
  3. Use Response.Redirect(String url, false) that bypasses the internal call to Response.End which terminates the current http thread.

I decided to use option 3 ,so I had to replace line 20 with the following code. I also decided to keep try-catch block , becuase I am going to show you something at the end of this post.

Page.Response.Redirect(Page.Request.Url.ToString(), false);

Last but not least, I would like to draw your attention to something here. If you have noticed, I am disposing my object in the finally block. In this MSDN document , it is said that calling Response.Redirect WILL NOT execute the finally block. Therefore, before any redirection or transfer of processing can occur, you must dispose of the objects. Well, my code here shows that finally block gets hit even after Response.Redirect!

Categories: MOSS 2007 Tags:
  1. Gopi Ega
    March 19th, 2008 at 16:09 | #1

    Thanks for the Information…
    in my case,I have FBA site and I need to verify the user against some webservice and if is existed in Webservice he shud be added to FBA site.
    i am trying the below code in
    1) SPWeb web = new SPSite(“http://localhost:112/sites/fba-ws/default.aspx”).OpenWeb();
    2) web.AllowUnsafeUpdates = true;
    3) _username = string.Format(“{0}:{1}”, “fbaUser”, UserId);
    4) SPUser spu = web.EnsureUser(_username);
    5) return true;
    I am getting the exception
    “Unable to evaluate expression because the code is optimized or a native frame is on top of the call stack” on line 4 and some times on line 1 itself
    any idea how to overcome this exception!
    how to execute the SpWeb.EnsureUser with out exception?
    Thanks In Advance

  2. Reza Alirezaei
    March 27th, 2008 at 14:04 | #2

    Hello Gopi,

    I am experiencing the exact same issue with SPUtility.ResolvePrincipal when I try to pass the “email” that I am getting from a web service call (CRM)and resolve it into a SPUser object. I did a lot of research (including getting hold of some MS guys), but I haven’t been able to find a solution. Living in FBA world , I had the luxury of using the following statement:

    string username = Membership.GetUserNameByEmail(strEmailAlias);

    and get the username based on the email address and move on, but in my case user was already added. Did you check to execute web.EnsureUser(_username); in an elevated privilage?

  3. Gopi Ega
    March 27th, 2008 at 14:36 | #3

    Hi Reza,
    Thanks for the response.
    Yeah I overcome this when I tried with elevated privilages.
    faced hell lot of exceptions to complete the custom FBA configuration
    Thanks

  4. Reza Alirezaei
    March 27th, 2008 at 15:06 | #4

    Gopi,

    That was the whole point of this post (first section) 🙂 – use elevated context because of the least privilege context that an anonymous user carries by default.Please make sure that you destroy the elevated context so security can not be compromised and also unmanaged resources that newly constructed SPWeb and SPSite hold are released.

  5. surya
    April 28th, 2008 at 08:02 | #5

    Hi,
    In my scenario, i need to modify the Quick Launch(QL) with a webpart based on user roles such as admin(diffirent nodes), visitor(limited nodes) to a default.aspx page in one my WSS 3.0 Web Site. I able to delete the existing Nodes in the QL /add new nodes when i logged-in as admin/contributor role. but i am able to add nodes for visitor. It shows to access denied page. i use the above ‘RunWithElevatedPrivileges’. but know use.
    Help me Plz!!!

    Thanks
    Surya

  6. Reza Alirezaei
    April 29th, 2008 at 16:26 | #6

    Please provide the exact code that fails on you. I might be able to help you.

  7. Nagaraju Joshi
    July 11th, 2008 at 10:25 | #7

    Thank you very much. I was getting the error “unable to evaluate expression….” and your solution resolved my problem. Thanks once again.

  8. sunil
    March 10th, 2009 at 07:40 | #8

    thanks Reza,

    it’s really very good artical

  9. cephusj
    July 1st, 2009 at 13:43 | #9

    You are a GODSEND! I was trying to customize Sharepoint mysites and the stupid redirect wouldnt work but thanks to your creative investigating. I realized why. Thanks so much.
    http://blogs.msdn.com/sharepoint/archive/2007/03/22/customizing-moss-2007-my-sites-within-the-enterprise.aspx

  10. Avi Kumar
    August 10th, 2009 at 13:58 | #10

    Hello

    I implemented your logic successfully when I am adding the users. Now I am in process of edit/update user program in which I want to populate user group and then select assigned group which I assigned when I created the user.

    Please advise

    Ashish

  11. Chris Alechko
    December 29th, 2009 at 15:44 | #11

    This was a life saver. I should have realized 4 hours ago that the real cause was access denied. I delegated upgraded permissions and was able to get the web no problem. thanks so much

  12. Vikash
    March 15th, 2010 at 01:11 | #12

    Hi
    If u use using block with web object as well then no need to dispose it explicitly .

    Thanks,
    Vikash

  13. Vijaya
    August 13th, 2010 at 06:05 | #13

    Hi Raza,
    Your solution helped me the first time. However, Im facing the error again even whem Im trying to run under elevated privileges. Here is the code snippet. Im getting the same error at the line where site is getting created.

    SPSecurity.RunWithElevatedPrivileges(delegate()
    {
    using (SPSite siteCollection = new SPSite(strLocationSiteURL))
    {
    siteCollection.AllowUnsafeUpdates = true;
    SPWeb newWeb = siteCollection.OpenWeb(); newWeb.AllowUnsafeUpdates = true;
    SPWebCollection subSites = newWeb.Webs; SPWeb newSiteWeb = subSites.Add(“hello”, “hello”, “”, 1033, “STS#0”, false, false);

    }

    });