Sergey Maskalik

Sergey Maskalik's blog

In the pursuit of mastery

If you are using simple incremental versioning like v39, v40 and etc., you are missing out. In software world every aspect has been thoroughly thought through, has a meaning and adds some kind of value. One of those aspects is project versioning. Many companies I worked at didn’t really give any thought on that subject and “homebrewed” some kind of simple incremental system. Most of the time that system would simply increment the version without giving any other information. A much better approach is to have versioning as a precise structure or rules to the project. Where all developers that work on the project understand and can differentiate between major, minor and patch releases.

It’s not hard and you don’t have to look far and re-use something that already works. So I encourage you to take a look at the formalized document by the cofounder of github that precisely identifies semantic versioning. Chances are next time you work on the open source project it will use the same system and you will be already familiar with it.

Enjoy.

ASP.NET MVC 4 introduced an important change in membership providers. Moving away from core membership to a more flexible and simpler SimpleMembershipProvider. Default “Internet Application” template initializes SimpleMembership by including an action filer InitializeSimpleMembership which gets gets added to the Account controller. So whenever you try to access account controller a filer would check if the SimpleMembershipInitializer was initialized and do the necessary work if needed.

In one of the applications I’m working on at the moment I wanted to only show MiniProfiler for logged in developers, so that required some changes to the default project structure. Since we want to have MiniProfiler visible on the entire site we need to make sure that membership provider gets initialized for all controllers. One way is to add InitializeSimpleMembershipAttribute to the global filters, however that would require you to hit the page twice since the action attribute fires after the Application_PostAuthorizeRequest (where we will be checking Roles) and the provider would not be initialized on the first request.

I’ve opted out to move the initialization logic from Action attribute to the Application_Start() of the Global.asax file. Since that only fires once per application I thought it would be a better place for it. So it looks like this:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...
       InitMembership();
    }
    private void InitMembership()
    {
        Database.SetInitializer<UsersContext>(null);

        try
        {
            using (var context = new UsersContext())
            {
                if (!context.Database.Exists())
                {
                    // Create the SimpleMembership database without Entity Framework migration schema
                    ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
                }
            }

            WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);

            if (!Roles.RoleExists("Developer"))
            {
                Roles.CreateRole("Developer");
            }
            if (!WebSecurity.UserExists("sergey"))
            {
                WebSecurity.CreateUserAndAccount("sergey", "password");
            }
            if (!Roles.GetRolesForUser("sergey").Contains("Developer"))
            {
                Roles.AddUserToRole("sergey", "Developer");
            }
        }
        catch (Exception ex)
        {
            throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
        }
    }
}

I left the default database creating with entity framework for now, I will most likely remove it later. The important part is that we create a new role “Developer” and assign it to our default user. Also, we can completely remove InitializeSimpleMembershipAttribute from the solution and remove it from AccountController.

In our MiniProfiler we will check if user has that role and if he or she doesn’t we will discard the results.

    protected void Application_BeginRequest()
    {
        MiniProfiler.Start();
    }

    protected void Application_PostAuthorizeRequest(object sender, EventArgs e)
    {
        if (!Request.IsAuthenticated || !Roles.GetRolesForUser(User.Identity.Name).Contains("Developer"))
        {
            MiniProfiler.Stop(discardResults: true);
        }
    }

    protected void Application_EndRequest()
    {
        MiniProfiler.Stop(); //stop as early as you can, even earlier with MvcMiniProfiler.MiniProfiler.Stop(discardResults: true);
    }

Unfortunately this will run MiniProfiler for all requests, one trick that was recommended on stackoverflow is to create a watermark cookie if use is in role so the profiler would only start if that cookie is present.

Enjoy!

When multiple threads are writing to the static field you need to make sure that the writing operation is atomic or only one thread can write at a time. One of the ways to ensure you static fields are thread safe is to use Interlocked class part from the System.Threading namespace.

Here is an example of a static cache that does clean up every 1000 saves.

public class QueryCache
{
   //static field that we need to make sure is thread safe
   private static int cacheCount;
   private const int MAX_ITEMS = 1000;
   static readonly System.Collections.Concurrent.ConcurrentDictionary<string, object> _cache = new System.Collections.Concurrent.ConcurrentDictionary<string, object>();
   public static void SaveToCache(string key, object value)
   {
      if(Interlocked.Increment(ref cacheCount) == MAX_ITEMS)
      {
          CleanUpCache();
      }
      _cache[key] = value;
   }
}

Since multiple threads can be writing to the cache at the same time, we have to make sure we don’t have a collision when incrementing a cacheCount file. Interlocked class has some other useful methods like Interlock.Exchange to set the variable to a specific value atomically.