SqlRoleProvider on IIS8 Express

2019-07-07 07:01发布

问题:

My web application (a WCF service) uses SqlRoleProvider, which works fine on Visual Studio Development Server. Switching it to IIS8 Express causes it to throw a NullReferenceException though:

Roles.IsUserInRole(username, role) // neither of them actually null

I could not find a hint for this exception in the IsUserInRole method documentation. Switching back to Visual Studio Development server makes it work. What is the cause of this exception, and how could I fix it properly? The project's target framework is .NET Framework 4.

Here is the configured connection string:

<add name="ConnectionString"
      connectionString="Data Source=.\sqlexpress;Initial Catalog=DevWeb;Integrated Security=True"
      providerName="System.Data.SqlClient" />

And this is the roleManager/providersnode:

<clear />
<add connectionStringName="ConnectionString" applicationName="MyApp" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider"/>

回答1:

What Vladimir said is true but doesn't actually explain what is happening. What throws the NullReferenceException is the EtwTrace code that's in IsUserInRole and GetRolesForUser. Everything else in the Roles class accounts for the fact that HttpContext.Current can be null. I found this by looking in the Microsoft Reference Source for "NET, Version 4.5" at http://referencesource.microsoft.com/netframework.aspx

In every other test environment I tried, the tracing level was not sufficient to trigger the NullReferenceException. It was only when I used IIS Express 8 after installing Visual Studio 2013 that I saw the issue and only in IIS Express.

What can you do about it?

One option is to enable "ASP.Net Compatibility Mode" for WCF. First, in the web.config, add the attribute aspNetCompatibilityEnabled="true" to the node <configuration><system.serviceModel><serviceHostingEnvironment>. Then opt your service class into the behavior by adding the attribute [System.ServiceModel.Activation.AspNetCompatibilityRequirements(RequirementsMode = System.ServiceModel.Activation.AspNetCompatibilityRequirementsMode.Allowed)] to the class definition.With this functionality enabled, HttpContext.Current will be populated by the time you go to request roles from the Roles class, assuming you're not working on a background thread like Vladimir mentioned (in which case you'll need to patch up the HttpContext.Current first). You can read more about ASP.NET Compatibility Mode for WCF at http://blogs.msdn.com/b/wenlong/archive/2006/01/23/516041.aspx.

The other option is to bypass the Roles class for these two methods. Instead of calling Roles.IsUserInRole, call Roles.Provider.IsUserInRole. Instead of calling Roles.GetRolesForUser, call Roles.Provider.GetRolesForUser. Each method has the same overloads available. You lose the trace stops and the local role cache but you bypass the null reference exception.



回答2:

If you calling Roles.IsUserInRole in different Thread then you should check HttpContext. In this case will be empty. So, for fix you should copy HttpContext from main thread to child thread.

        var context = HttpContext.Current;
        Thread thread = new Thread(delegate() {
            if (HttpContext.Current == null)
                HttpContext.Current = context;
        });

        thread.Start();


回答3:

Fairly sure your issue is going to be with the database and the permission of the account accessing it. Try adding your IIS account to the sa priv and see if the matter resolves. If it does then you have a missing permission.