Archive for the ‘.NET 4.0’ Category.

Configuring an ASP.NET Web Application to Use a Windows Server AppFabric Cache for Session State

Last week I spent some time setting up Windows Server AppFabric Cache in anticipation of additional tasks this week.  The first task is configuring an ASP.NET web application to use Windows Server AppFabric Caching for the Session State Provider.  This allows the web application to spread session objects across the entire cache cluster, resulting in greater scalability.

Below is a walkthrough on how to configure this scenario.  In addition to this post, I recommend you take a look at this article on MSDN.

  1. Thoroughly review Getting Started with Windows Server AppFabric Cache to get everything setup.
  2. Open up the Cache PowerShell console (Start –> Windows Server AppFabric –> Caching Administration Windows PowerShell).  This will automatically import the DistributedCacheAdministration module and use the CacheCluster.
  3. Start the Cache Cluster (if not already started).  Run the following command in the PowerShell console:
    Start-CacheCluster
  4. Create a new cache that you will leverage for your session state provider.  Run the following command in the PowerShell console:
    New-Cache MySessionStateCache
  5. Create a new ASP.NET Web Application in Visual Studio 2010 targeting .NET 4.0.  This will create a sample project, complete with master page which we’ll leverage later on.
  6. Add references to the Microsoft.ApplicationServer.Caching.Client and Microsoft.ApplicationServer.Caching.Core.  To do this, use the following steps (thanks to Ron Jacobs for the insight):
    1. Right-click on your project and select Add Reference.
    2. Select the Browse tab.
    3. Enter the following folder name, and press enter:
      %windir%\Sysnative\AppFabric
    4. Locate and select both Microsoft.ApplicationServer.Caching.Client and Microsoft.ApplicationServer.Caching.Core assemblies.
  7. Add the configSections element to the web.config file as the very first element element in the configuration element:
    <!--configSections must be the FIRST element -->
    
    <configSections>
    
      <!-- required to read the <dataCacheClient> element -->
    
      <section name="dataCacheClient"
    
            type="Microsoft.ApplicationServer.Caching.DataCacheClientSection,
    
              Microsoft.ApplicationServer.Caching.Core, Version=1.0.0.0,
    
              Culture=neutral, PublicKeyToken=31bf3856ad364e35"
    
            allowLocation="true"
    
            allowDefinition="Everywhere"/>
    
    </configSections>
  8. Add the dataCacheClient element to the web.config file, after the configSections element.  Be sure to replace YOURHOSTNAME with the name of your cache host.  In the PowerShell console you can get the HostName (and CachePort) by starting or restarting your cache).
    <dataCacheClient>
    
      <!-- cache host(s) -->
    
      <hosts>
    
        <host
    
            name="YOURHOSTNAME"
    
            cachePort="22233"/>
    
      </hosts>
    
    </dataCacheClient>
  9. Add the sessionState element to the web.config file in the system.web element.  Be sure that the cacheName is the same as the cache you created in step 4.
    <sessionState mode="Custom" customProvider="AppFabricCacheSessionStoreProvider">
    
      <providers>
    
        <!-- specify the named cache for session data -->
    
        <add
    
          name="AppFabricCacheSessionStoreProvider"
    
          type="Microsoft.ApplicationServer.Caching.DataCacheSessionStoreProvider"
    
          cacheName="MySessionStateCache"
    
          sharedId="SharedApp"/>
    
      </providers>
    
    </sessionState>
  10. Now, we need a quick and easy way to test this.  There are many ways to do this, below is mine.  I loaded data into session, then created a button that writes the session data into a JavaScript alert.  Quick and easy:
    protected void Page_Load(object sender, EventArgs e)
    
    {
    
        // Store information into session
    
        Session["PageLoadDateTime"] = DateTime.Now.ToString();
    
    
    
        // Reference the ContentPlaceHoler on the master page
    
        ContentPlaceHolder mpContentPlaceHolder =
    
            (ContentPlaceHolder)Master.FindControl("MainContent");
    
        if (mpContentPlaceHolder != null)
    
        {
    
            // Register the button
    
            mpContentPlaceHolder.Controls.Add(
    
                GetButton("btnDisplayPageLoadDateTime", "Click Me"));
    
        }
    
    }
    
    
    
    // Define the button
    
    private Button GetButton(string id, string name)
    
    {
    
        Button b = new Button();
    
        b.Text = name;
    
        b.ID = id;
    
        b.OnClientClick = "alert('PageLoadDateTime defined at " +
    
            Session["PageLoadDateTime"] + "')";
    
        return b;
    
    }
  11. Now, hit control-F5 to start your project.  After it loads, click the button labeled “Click Me” – you should see the following alert:
    ASP.NET using Cache for Session State

That’s it!  You have now configured your ASP.NET web application to leverage Windows Server AppFabric Cache to store all Session State. 

While I was putting this together, I encountered two errors.  I figured I’d share them here, along with resolution, in case any of you encounter the same problems along the way.

    Configuration Error
    
      
    Description: An error occurred during the processing of a configuration
    
    file required to service this request. Please review the specific error
    
    details below and modify your configuration file appropriately.
    
    Parser Error Message: ErrorCode<ERRCA0009>:SubStatus<ES0001>:Cache
    
    referred to does not exist. Contact administrator or use the Cache
    
    administration tool to create a Cache.


    If you received the above error message, it’s likely that the cacheName specified in the sessionState element is wrong.  Update the cacheName to reflect the cache you created in step #4.

    Configuration Error
    
      
    Description: An error occurred during the processing of a configuration
    
    file required to service this request. Please review the specific error
    
    details below and modify your configuration file appropriately.
    
    Parser Error Message: ErrorCode<ERRCA0017>:SubStatus<ES0006>:There is
    
    a temporary failure. Please retry later. (One or more specified Cache
    
    servers are unavailable, which could be caused by busy network or
    
    servers. Ensure that security permission has been granted for this
    
    client account on the cluster and that the AppFabric Caching Service
    
    is allowed through the firewall on all cache hosts. Retry later.)


    If you received the above error message, it’s likely that the host name specified in the dataCacheClient is wrong.  Update the dataCacheClient host name to reflect the name of your host.  Note: it’s likely that it’s just your machine name.

Hope this help!

Real-World Patterns for Cloud Computing at TechEd NA 2010

image It was an amazing TechEd NA 2010, and I admit that it took me a few days to recover.  Between the heat and humidity, great times with friends, and good food, I managed to spend a bit of time at the conference.

I had the pleasure of co-presenting with Jerome Schulist, a solutions architect at the Tribune Company.  Jerome is one of the architects that engineered the solution that has allowed the Tribune Company to store and process terabytes of data on the Windows Azure platform.  This solution involves a number of really interesting scenarios, including:

  • Parallelized upload of terabytes of digital content into Windows Azure blob storage using .NET Framework 4.0
  • Best practices for uploading a massive amount of content
  • Scaling strategy for Windows Azure blob storage through multiple storage accounts and a “round robin” pattern
  • Content reprocessing with Windows Azure worker roles
  • Automatic scale-out and scale-back of worker roles through queue lengths

For detailed information on this solution, you can take a look at the Tribune Company’s Windows Azure case study or you can watch our TechEd NA 2010 presentation here:

Get Microsoft Silverlight

As promised in the session, you can find the final code built during the session below.  Just remember to update the config files with your own credentials.

Host WCF Services in IIS with Service Bus Endpoints

Update: To see how to leverage Windows Azure AppFabric Autostart to activate the WCF Service, please see AutoStart WCF Services to Expose them as Service Bus Endpoints.


Vishal Chowdhary, a Senior Test Lead on the Azure AppFabric team, recently posted a whitepaper on hosting WCF services with Service Bus endpoints from IIS.  This whitepaper provides two solutions to a (previously) significant challenge in hosting WCF services in IIS that connect to the Azure AppFabric Service Bus.

The primary challenge is activation. As Vishal writes, “For the on-premise WCF service to start receiving messages from the Service Bus in the cloud (aka Relay Service), the on-premises service opens an outbound port and creates a bidirectional socket for communication.  It connects to the Service Bus, authenticates itself, and starts listening to calls from the relay service before the client sends its requests.”  He goes on to say that “IIS/WAS relies on message-based activation & will launch the host only after the first request comes in.”  Consequently, until the first message is received by IIS the service will never establish a connection to the Service Bus; with no connection to the Service Bus, it will never receive a message.  A bit of a dilemma.

In the whitepaper, Vishal points out two ways to resolve this challenge:

  • IIS Application Warm-Up
  • ASP.NET 4.0 Auto-Start

In this post, I’m going to highlight exactly how to go about using IIS Application Warm-Up to get a WCF service hosted in IIS 7.5 to receive messages from the Service Bus.  This post borrows heavily from Visha’s whitepaper; I strongly suggest you spend the time to read the entire paper.

  1. If you’re using .NET 4.0, you must setup .NET 4.0 to work with the Azure AppFabric SDK.
  2. Create a new ASP.NET Web Application project called EchoSample in Visual Studio 2010 using .NET 4.0.
  3. To validate this approach, we want this project hosted in IIS.  Right-click the project and choose Properties.  Select the Web tab, and switch from Use Visual Studio Development Server to Use Local IIS Web server and click Create Virtual Directory.
  4. Add the Microsoft.ServiceBus reference from the “C:\%Program Files%\Windows Azure platform AppFabric SDK\V1.0\Assemblies\” folder.
  5. You have to create a custom BehaviorExtensionElement for the ServiceRegistrySettings to make the discoverability policy ‘Public’ in the configuration file.  Consequently, we need to create a class that we’ll call MyServiceRegistrySettingsElement that inherits the BehaviorExtensionElement.
public class MyServiceRegistrySettingsElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(ServiceRegistrySettings); }
    }
    protected override object CreateBehavior()
    {
        return new ServiceRegistrySettings()
        {
            DiscoveryMode = this.DiscoveryMode,
            DisplayName = this.DisplayName
        };
    }
    [ConfigurationProperty("discoveryMode", DefaultValue = DiscoveryType.Private)]
    public DiscoveryType DiscoveryMode
    {
        get { return (DiscoveryType)this["discoveryMode"]; }
        set { this["discoveryMode"] = value; }
    }
    [ConfigurationProperty("displayName")]
    public string DisplayName
    {
        get { return (string)this["displayName"]; }
        set { this["displayName"] = value; }
    }
}
  1. Now, let’s add a new WCF Service called EchoService to the project.  Remove the existing method in the ServiceContract and create the following GetData method in the IEchoService.cs file.
[OperationContract]
string GetData(int value);
  1. Also, update the EchoService.svc.cs with the implementation of the GetData method.
public string GetData(int value)
{
    if (value < 0)
        throw new ApplicationException("Negative values not allowed!!!");

    Thread.Sleep(value);
    return string.Format("You entered: {0}", value);
}
  1. Now we need to update the web.config settings.  This is fairly extensive. Be sure and replace YOUR_NAMESPACE, YOUR_ISSUER_NAME, and YOUR_ISSUER_SECRET with your own values.
<system.serviceModel>
  <extensions>
    <behaviorExtensions>
      <add name="ServiceRegistrySettings"
            type="EchoSample.MyServiceRegistrySettingsElement, EchoSample,
                  Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </behaviorExtensions>
  </extensions>
  <services>
    <clear />
    <service behaviorConfiguration="MyServiceTypeBehavior"
              name="EchoSample.EchoService">
      <endpoint
         address="http://localhost/EchoSample/EchoService.svc/LocalEchoService"
         binding="basicHttpBinding"
         bindingConfiguration="BasicHttpConfig"
         name="Basic" contract="EchoSample.IEchoService" />
      <endpoint
         address="https://YOUR_NAMESPACE.servicebus.windows.net/EchoServiceHttp/"
         behaviorConfiguration="sharedSecretClientCredentials"
         binding="basicHttpRelayBinding"
         bindingConfiguration="HttpRelayEndpointConfig"
         name="RelayEndpoint"
         contract="EchoSample.IEchoService" />
      <endpoint
         address="sb://YOUR_NAMESPACE.servicebus.windows.net/EchoServiceNetTcp/"
         behaviorConfiguration="sharedSecretClientCredentials"
         binding="netTcpRelayBinding"
         bindingConfiguration="NetTcpRelayEndpointConfig"
         name="RelayEndpoint"
         contract="EchoSample.IEchoService" />
    </service>
  </services>
  <bindings>
    <basicHttpBinding>
      <binding name="BasicHttpConfig" />
    </basicHttpBinding>
    <!--service bus binding-->
    <basicHttpRelayBinding>
      <binding name="HttpRelayEndpointConfig">
        <security relayClientAuthenticationType="RelayAccessToken" />
      </binding>
    </basicHttpRelayBinding>
    <netTcpRelayBinding>
      <binding name="NetTcpRelayEndpointConfig">
        <security relayClientAuthenticationType="RelayAccessToken" />
      </binding>
    </netTcpRelayBinding>
  </bindings>
  <behaviors>
    <endpointBehaviors>
      <behavior name="sharedSecretClientCredentials">
        <transportClientEndpointBehavior credentialType="SharedSecret">
          <clientCredentials>
            <sharedSecret issuerName="YOUR_ISSUER_NAME"
                          issuerSecret="YOUR_ISSUER_SECRET" />
          </clientCredentials>
        </transportClientEndpointBehavior>
        <ServiceRegistrySettings discoveryMode="Public" />
      </behavior>
    </endpointBehaviors>
    <serviceBehaviors>
      <behavior name="MyServiceTypeBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>


At this point, once you compile and build the solution, the service will not automatically connect to the Service Bus; this is because IIS/WAS waits until the first service call to activate.  Consequently, if you load the WCF service in the browser it will activate the service and establish a connection to the Service Bus (you can confirm by checking https://YOUR_NAMESPACE.servicebus.windows.net/).  So, we’re close, but not yet there.

To get the service to automatically establish the connection to the Service Bus, we’ll use the Application Warm-Up extension for IIS 7.5.

  1. Download and install the Application Warm-Up extension for IIS 7.5.  This gives us the ability to proactively load and initialize processes before the first request arrives.  In addition to improving responsiveness it also gives us the ability to connect our WCF service to the Azure AppFabric Service Bus.
  2. In IIS, select your virtual application EchoSample.  Double-click the Application Warm-Up feature, and click Settings.  Check the Start Application Pool ‘ASP.NET v4.0’ when service started checkbox.

Application Warm-Up settings

  1. Add a new request to register EchoService.svc as a warm-up request for the application.  Right-click and choose Add Request.  Enter EchoService.svc, and click OK.  You should now see it in the Request URL list.

Application Warm-Up add request

Application Warm-Up

And that’s it!  The service is now automatically started and “warmed up” by IIS.  To test, recycle the Application Pool and restart the web site.  Then, hit your Service Bus endpoint and confirm that you’re services are running.

Publicly Listed Services

Now, even if we restart the computer, the WCF service will reestablish the connection to the Service Bus because IIS 7.5, through the Application Warm-Up Extensions, will automatically refresh.

Now, to complete the test, let’s build a quick Console application to connect to the WCF service via the Service Bus.

  1. Create a new Console Application project called Client.
  2. Add a reference to the Microsoft.ServiceBus and System.ServiceModel.
  3. Add a link to the IEchoService.cs file in the EchoSample project.  Right-click the project, choose Add Existing, and change Add to Add as Link.

Add Existing Item - Add As Link 

  1. Update the Program.cs file with the following code.  Be sure and replace YOUR_NAMESPACE, YOUR_ISSUER_NAME, and YOUR_ISSUER_SECRET with your own values.
class Program
{
    static void Main(string[] args)
    {
        // Determine the system connectivity mode based on the command line
        // arguments: -http, -tcp or -auto  (defaults to auto)
        ServiceBusEnvironment.SystemConnectivity.Mode = GetConnectivityMode(args);
        string serviceNamespace = "YOUR_NAMESPACE";
        string issuerName = "YOUR_ISSUER_NAME";
        string issuerSecret = "YOUR_ISSUER_SECRET";
        // create the service URI based on the service namespace
        Uri serviceUri = ServiceBusEnvironment.CreateServiceUri("sb",
            serviceNamespace, "EchoServiceNetTcp");
        //Uri serviceUri = ServiceBusEnvironment.CreateServiceUri(
        //    "https", serviceNamespace, "EchoServiceHttp");
        // create the credentials object for the endpoint
        TransportClientEndpointBehavior sharedSecretServiceBusCredential =
            new TransportClientEndpointBehavior();
        sharedSecretServiceBusCredential.CredentialType =
            TransportClientCredentialType.SharedSecret;
        sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerName =
            issuerName;
        sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerSecret =
            issuerSecret;
        // create the channel factory loading the configuration
        //BasicHttpRelayBinding myBinding = new BasicHttpRelayBinding();
        NetTcpRelayBinding myBinding = new NetTcpRelayBinding();
        EndpointAddress myEndpoint = new EndpointAddress(serviceUri);
        ChannelFactory<IEchoService> channelFactory =
            new ChannelFactory<IEchoService>(myBinding, myEndpoint);
        // apply the Service Bus credentials
        channelFactory.Endpoint.Behaviors.Add(sharedSecretServiceBusCredential);
        // create and open the client channel
        IEchoService channel = channelFactory.CreateChannel();
        Console.WriteLine("Enter text to echo (or [Enter] to exit):");
        string input = Console.ReadLine();
        while (input != String.Empty)
        {
            try
            {
                Console.WriteLine("Server echoed: {0}",
                    channel.GetData(Int32.Parse(input)));
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: " + e.Message);
            }
            input = Console.ReadLine();
        }
        if (((IClientChannel)channel).State != CommunicationState.Faulted)
            ((IClientChannel)channel).Close();
        else
            ((IClientChannel)channel).Abort();
        channelFactory.Close();
    }
    static ConnectivityMode GetConnectivityMode(string[] args)
    {
        foreach (string arg in args)
        {
            if (arg.Equals("/auto", StringComparison.InvariantCultureIgnoreCase)
                 || arg.Equals("-auto", StringComparison.InvariantCultureIgnoreCase))
            {
                return ConnectivityMode.AutoDetect;
            }
            else if (arg.Equals("/tcp", StringComparison.InvariantCultureIgnoreCase)
                 || arg.Equals("-tcp", StringComparison.InvariantCultureIgnoreCase))
            {
                return ConnectivityMode.Tcp;
            }
            else if (arg.Equals("/http", StringComparison.InvariantCultureIgnoreCase)
                 || arg.Equals("-http", StringComparison.InvariantCultureIgnoreCase))
            {
                return ConnectivityMode.Http;
            }
        }
        return ConnectivityMode.AutoDetect;
    }


When you run the console application, it will connect to your WCF service through the Service Bus.  Run it to validate. You can also uncomment some of the code to use BasicHttpRelayBinding instead of NetTcpRelayBinding to try out a different configuration.

The ability to host a WCF service in IIS that exposes itself on the Service Bus is a significant milestone.  This opens up a number of fantastic opportunities and scenarios that otherwise would have been extremely difficult to accomplish.

Using the .NET Framework 4.0 with the Azure AppFabric SDK

The other day I attempted to build a sample application that communicated with the Azure AppFabric Service Bus by creating a Console application targeting the .NET Framework 4.0.  After adding a reference to Microsoft.ServiceBus I was bewildered to see that my Service Bus bindings in the system.ServiceModel section were not recognized.

I soon realized that the issue was the machine.config file.  When you install the Azure AppFabric SDK the relevant WCF extensions are added to the .NET Framework 2.0 machine.config file, which is shared by .NET Framework 3.0 and 3.5.  However, .NET Framework 4.0 has its own machine.config file, and the SDK will not update the WCF extensions.

Fortunately, there’s an easy solution to this issue: use the CLR’s requiredRuntime feature.

  1. Create a configuration file named RelayConfigurationInstaller.exe.config in the “C:\%Program Files%\Windows Azure platform AppFabric SDK\V1.0\Assemblies\” folder with the following code:
<?xml version ="1.0"?><configuration>  <startup>    <requiredRuntime safemode="true"       imageVersion="v4.0.30319"       version="v4.0.30319"/>  </startup></configuration>
  1. Open up an elevated Visual Studio 2010 Command Prompt, browse to the directory, and run: RelayConfigurationInstaller.exe/ i

Your .NET Framework 4.0 machine.config file will now have the required configuration settings for the Service Bus bindings.  Thanks to Vishal Chowdhary for the insight!