Multiple apps sharing a single app_data for security provider produces: Access denied creating App_Data subdirectory
<p>I have multiple asp.net (framework 4.0, under iis7) apps that are all sharing the same forms authentication using the standard security provider.  I've changed the machine keys so they all match between my apps and it works great.  I login in my root app and then I don't have to login anymore in any of my child apps.</p>

<pre><code>App Structure: 
Main App
    User Folder
        App1
    Admin Folder
        App2
</code></pre>

<p>Entering the site through the main app and logging in and navigating to the sub apps all works fine.  I start having problems if I try to jump directly to a sub app:
<a href="http://localhost/User/App1" rel="nofollow">http://localhost/User/App1</a>
I get redirected to the login page (/login.aspx) as expected (where I use a standard login control), enter my credentials and when it sends me to the retunrURL I get:
Access denied creating App_Data subdirectory</p>

<p>It's as if the security provider is now trying to find the mdf file in user\app1\app_data.</p>

<p>I've tried:</p>

<p>Hardcoding the path in a connection string for AttachDBFilename instead of using |DataDirectory|</p>

<pre><code>&lt;add name="LocalSqlServer2" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=C:\inetpub\wwwroot\App_Data\mydb.mdf;User Instance=true" providerName="System.Data.SqlClient"/&gt;
</code></pre>

<p>Hardcoding a path application_start event in the global.asax for app1
AppDomain.CurrentDomain.SetData("DataDirectory", @"C:\inetpub\wwwroot\App_Data\mydb.mdf");</p>

<p>Nothing works.</p>

<p>I can intercept and ignore the returnurl by forcing a redirect to the root app default page but that's not exactly a solution to the issue.</p>

<pre><code>protected virtual void Login1_OnLoggedIn(Object sender, EventArgs e)
    {
        Response.Redirect("~/Default.aspx");
    }
</code></pre>

<p><strong>ANSWER:</strong></p>

<p>I was on the right track.  You want to define your own connecting string with a hard coded path (do NOT use |DataDirectory|):</p>

<pre><code>&lt;connectionStrings&gt; 
    &lt;add name="LocalSqlServer2" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=C:\inetpub\wwwroot\App_Data\mydb.mdf;User Instance=true" providerName="System.Data.SqlClient"/&gt;
&lt;/connectionStrings&gt;
</code></pre>

<p>Tell your membership provider to use the new connection string:</p>

<pre><code>&lt;membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="20"&gt;
  &lt;providers&gt;
    &lt;clear/&gt;
    &lt;add name="SqlProvider"
        type="System.Web.Security.SqlMembershipProvider"
        connectionStringName="LocalSqlServer2"
        ......  
</code></pre>

<p>And the critical step I forgot was to do it also for your role provider:</p>

<pre><code>        &lt;roleManager enabled="true" cacheRolesInCookie="true" defaultProvider="SqlRoleProvider" &gt;
        &lt;providers&gt;
            &lt;clear/&gt;
            &lt;add name="SqlRoleProvider"
               type="System.Web.Security.SqlRoleProvider"
                connectionStringName="LocalSqlServer2"              
                applicationName="/" /&gt;
        &lt;/providers&gt;
    &lt;/roleManager&gt;
</code></pre>

<p>And if you are using a profile provider then that too.</p>
