1

My ASP.NET MVC application is using Application Services for Membership. For a number of reasons I am not using the Application Services Profiles. I am managing profiles in a bunch of bespoke tables that are connected to the Membership tables. My Domain Model consists of classes that map with Entity Framework (DbContext) to my tables (including profile tables but not the Application Services Tables).

When a new user is created by the membership provider, I want to do a bunch of things in my profile tables and rollback the membership creation if any of my profile preparation steps fails.

So I altered the registration method to include a call to the methods that do the work I want and placed it all in a TransactionScope. The code works fine when there is no Transaction, but using a TransactionScope, as soon as the context.SaveChanges() method is called from within the Repository Class (which is in a separate assembly), I get the error: "The provider did not return a ProviderManifestToken string."

using (TransactionScope scope = new TransactionScope())
{
System.Web.Security.MembershipUser newUser = Membership.CreateUser
    (model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);

if (createStatus == MembershipCreateStatus.Success)
{
    FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */);

    // Create the profile and permissions
    bool profileCreation = repository.NewUser(newUser.UserName, newUser.ProviderUserKey);

    if (profileCreation)
    {
        scope.Complete();
        return RedirectToAction("List", "Project");
    }
    else scope.Dispose();
}
else
{
    scope.Dispose();
    ModelState.AddModelError("", ErrorCodeToString(createStatus));
}                    
}

Is it possible for transactions to handle connections to the database that are coming from Entity Framework and the Application Services code (I don't know what connection method it uses)? If so, how do I achieve this?

I would be very grateful for any help, Dave

dave walker
  • 3,058
  • 1
  • 24
  • 30

2 Answers2

2

It sounds like maybe EF or your Membership Provider is not enlisted in the transaction (EnlistTransaction). Are the SQL Connections for each participant to the same server (obviously different data stores)? You could try performing the transaction scope using only the Membership Provider, or only the Entity Framework to see which one is causing the grief.

See this post regarding transaction scope usage.

You also don't need to call scope.Dispose() since you are in a using statement. This is implicitly done for you.

Community
  • 1
  • 1
SliverNinja - MSFT
  • 31,051
  • 11
  • 110
  • 173
0

Thank you SilverNinja for the advice. The answer turned out to be quite simple: Turn on Distributed Transaction Coordinator (MSDTC) from the Services window.

dave walker
  • 3,058
  • 1
  • 24
  • 30