Category Archives: ASP.NET

Visual Studio 2013 Settings.settings and Web.config sync Issue

.Net projects can include settings that allow the runtime of an application to be altered based on values present in the Web.config file for the application. Modifying these values doesn’t require the application to be re-compiled when they are changed, which is advantageous in production systems where settings need to be altered without disrupting the environment.

Moving a project from TFS 2008 to TFS 2013 caused some issues with syncing the Web.config with the Settings.settings file. Changes made to the Web.config and then saved usually persist back to the settings file automagically. With a deployed application modifying the Web.config settings was not affecting the application. When the project was deployed the Settings.settings file had a value that wasn’t the same as the Web.config. Strangely, after deploying the application the application ignored changes made to the Web.config.

After a few minutes of head scratching I peeked into the Settings.Designer.cs file and found the setting was not updating when changed in the Web.config. I manually changed the string returned by the setting and saved the file. Like magic, the Web.config started updating the Settings.setting.

Capture

[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("test")]
public string Setting {
   get {
      return ((string)(this["Setting"]));
   }
}

Capture

Capture

SignalR with Load Balanced IIS and SQL Messaging Backplane

A requirement of a recent project was to have asynchronous communication between a set of load balanced servers and multiple web clients. SignalR has the ability to work across multiple servers using a SQL server backplane through the NuGet package. I found a good guide on asp.net‘s website to get the server up and running, but all of the examples involved sending messages to all users at the same time.

Clients.All.addNewMessageToPage(name, message);

In my scenario I needed to signal each user individually.

Clients can be sent to different servers behind the load balancer as they browse the site. Consider this scenario:

1. Client A makes a request to be added to the notification list.
2. The load balancer sends Client A to Server 1.
3. Server 1 registers Client A with it’s local instance of SignalR.
4. Client B requests to notify Client A that some event has occurred.
5. The load balancer sends Client B to Server 2.
6. Server 2 is not aware of the connection between Server 1 and Client A, and the request fails.

With the SQL backplane all of the servers share the same connection list, allowing a message to be sent to a Client A from a Server 2, even though Client A registered with Server 1.

In order to send a message to a single client the server needs to know the specific connection ID to send the message to. SignalR doesn’t offer a way to store a connection ID “key value pair”, so I created one on my own.

In my Hub.cs file I added a method that runs during the client registration:

public void registerClient(long SpecificIdentifier)
{
   HubMethods.RegisterClient(SpecificIdentifier, Guid.Parse(Context.ConnectionId));
}

In the RegisterClient method I store the SignalR connection ID along with a identifier specific to my application. A table stores the ID, the SignalR connection ID, and a timestamp. A procedure was created to clear out the table nightly.

public static void RegisterClient(long SpecificIdentifier, Guid ConnectionID)
{
   using (dbEntities db = new dbEntities())
   {
      Notification notification = db.Notifications.Where(x => x.ID == SpecificIdentifier).FirstOrDefault();

      if (notification == null)
      {
         notification = new Notification()
         {
            ID = SpecificIdentifier,
            ConnectionID = ConnectionID,
            LastModified = DateTime.UtcNow,
         };

         db.Notifications.Add(notification);
      }
      else
      {
         notification.ID = SpecificIdentifier;
         notification.ConnectionID = ConnectionID;
         notification.LastModified = DateTime.UtcNow;
      }

      db.SaveChanges();
   }
}

With the SQL backplane all of the servers share the same connection list, allowing a message to be sent to a Client A from a Server 2, even though Client A registered with Server 1.

When it comes time to send a message to a client, the notification method simply looks up the SignalR connection ID based on the ID specific to our application. The SQL backplane gathers the required information automatically based on the connection ID and the message is sent.

public static void NotifyClient(long SpecificIdentifier, Hub.Statuses Status)
{
   using (dbEntities = new dbEntities ())
   {
      Notification notification = db.Notifications.Where(x => x.ID == SpecificIdentifier).FirstOrDefault();

      if (notification != null)
      {
         String message = String.Empty;

         if (Status== Hub.Statuses.Confirmed)
         {
            message = "Here's the message for confirmation";
         }
         else if (Status == Hub.Statuses.Failed)
         {
            message = "Here's the message for failure";
         }

         try
         {
            IHubContext notificationHub = GlobalHost.ConnectionManager.GetHubContext<Hub>();
            notificationHub.Clients.Client(notification.ConnectionID.ToString()).addMessage(message);
         }
         catch (Exception ex)
         {
            ex.LogToElmah();
         }
      }
      else
      {
         throw new Exception("Unable to find connection");
      }
   }
}