Ask Learn
Preview
Ask Learn is an AI assistant that can answer questions, clarify concepts, and define terms using trusted Microsoft documentation.
Please sign in to use Ask Learn.
Sign inThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
A custom Role Provider is a very useful tool for adding custom authorization to your ASP.NET and/or ASP.NET MVC applications. A common use for a custom Role Provider is when you have role information stored in a data store that differs from the schema that is used by the built-in ASP.NET Role Providers. In this case, ASP.NET provides a abstract RoleProvider class that can be used to implement the custom provider. This contains role-specific methods such as: CreateRole, DeleteRole, GetRolesForUser, etc. In a custom Role Provider, you provide the implementation of these methods using your database access mechanism of choice. The MSDN documentation for implementing a custom Role Provider is a good place to start if you want to learn more about this.
In this post, I am NOT going to detail the steps in creating a custom Role Provider. Examples of this can be found all over the internet. Rather, I am going to talk about a recent gotcha with implementing a custom Role Provider that was encountered on a project that I am working on.
The following preconditions are used in our custom implementation:
Here is a quick snippet of the initial custom provider that we implemented:
1: public class CustomRoleProvider : RoleProvider
2: {
3: private IRoleRepository roleRepository;
4:
5: public CustomRoleProvider()
6: : this(ServiceLocator.Current.GetInstance<IRoleRepository>())
7: {
8: }
9:
10: public CustomRoleProvider(IRoleRepository roleRepository)
11: {
12: this.roleRepository = roleRepository;
13: }
14:
15: // Role Provider Abstract members
16:
17: // ...
18:
19: public override void CreateRole(string roleName)
20: {
21: Role newRole = Role.CreateFromName(roleName);
22: this.roleRepository.Add(newRole);
23: }
24:
25: // ...
26: }
At the outset, this seemed to be working great. The application functioned. The unit tests passed. Our roles that were stored in the database were being managed by the custom Role Provider. Then we started to notice some weird behavior.
I had a facepalm moment and quickly realized that I had neglected to remember a very important part of implementing a custom Role Provider. During the initialization of an ASP.NET application, a single instance of the RoleProvider class is instantiated and used for the life of the application. Of course, this all made perfect sense now. The Entity context for the role provider was effectively a singleton since is was only being injected at the beginning of the application. It didn’t take long for this context to become stale if changes were made to the roles during other requests.
The MSDN fine print does talk about this:
For each role provider specified in the configuration for an application, ASP.NET instantiates a single role-provider instance that is used for all of the requests served by an HttpApplication object. As a result, you can have multiple requests executing concurrently. ASP.NET does not ensure the thread safety of calls to your provider. You will need to write your provider code to be thread safe. For example, creating a connection to a database or opening a file for editing should be done within the member that is called, such as AddUsersToRoles , rather than opening a file or database connection when the Initialize method is called.
“Implementing a Role Provider (Threading Section)", Microsoft Developer Network Library, https://msdn.microsoft.com/en-us/library/8fw7xh74.aspx
The quick fix for this problem was to change the custom role provider to use a new IRoleRepository without a lifetime manager (returning a new instance for every call to GetInstance()) for each call to a method on the provider:
1: public class CustomRoleProvider : RoleProvider
2: {
3: public CustomRoleProvider()
4: {
5: }
6:
7: // Role Provider Abstract members
8:
9: // ...
10:
11: public override void CreateRole(string roleName)
12: {
13: Role newRole = Role.CreateFromName(roleName);
14:
15: IRoleRepository roleRepository = ServiceLocator.Current.GetInstance<IRoleRepository>(“NoLifetime”);
16: roleRepository.Add(newRole);
17: }
18:
19: // ...
20: }
So what have we learned?
Anonymous
May 11, 2009
PingBack from http://asp-net-hosting.simplynetdev.com/tip-entity-framework-unity-and-the-aspnet-roleprovider-%e2%80%93-read-the-msdn-fine-print/
Anonymous
May 11, 2009
Thank you for submitting this cool story - Trackback from DotNetShoutout
Ask Learn is an AI assistant that can answer questions, clarify concepts, and define terms using trusted Microsoft documentation.
Please sign in to use Ask Learn.
Sign in