Question

In a .NET 4.0 project, I'm experiencing that a call to System.Web.Security.Roles.RoleExists within a System.Transactions.TransactionScope fails due to MSDTC not being enabled on my development machine. The role manager's data source is LocalDB and the provider is of type System.Web.Providers.DefaultRoleProvider. I've installed NuGet package Microsoft.AspNet.Providers.LocalDB, which I believe supplies the role manager's provider.

What is it that's causing MSDTC to be required?

Code

The failing call:

using (var ts = new TransactionScope())
{
    Roles.RoleExists("Administrator");
}

The relevant configuration sections from web.config:

<connectionStrings>
  <clear />
  <add name="MembershipConnection" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=MyDB;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\mydb.mdf" providerName="System.Data.SqlClient" />
</connectionStrings>

<roleManager enabled="true" defaultProvider="DefaultRoleProvider">
  <providers>
    <remove name="AspNetSqlRoleProvider" />
    <add connectionStringName="MembershipConnection" applicationName="/" name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
    </providers>
  </roleManager>

Test project

I've created a test ASP.NET MVC 4 Internet application that demonstrates the issue. Download the TestBundles Visual Studio 2012 solution, debug the app and click the 'Log in' link. As I've made the Login action try to validate a role, you should get an exception unless you have enabled MSDTC on your machine.

public ActionResult Login(string returnUrl)
{
    using (var ts = new TransactionScope())
    {
        Roles.RoleExists("Administrator");
    }

    ViewBag.ReturnUrl = returnUrl;
    return View();
}
Was it helpful?

Solution

I was having this same problem. Then I figured out that this was only happening when Membership was being initialized for the first time. If you make any call to any Membership methods before entering the TransactionScope it will not have to initialize and promote to DTC.

As a bit of a hack (that works well), add the following to your app startup:

    protected void Application_Start()
    {
        Membership.GetNumberOfUsersOnline();
    }

This will cause membership to be initialized and then you will not have to enlist the DTC inside transaction scopes from then on.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top