Hosting ASP.Net Application Services in Azure and Implement ClientApplicationServices
ASP.NET application services are built-in Web services that provide access to features such as forms authentication, roles, and profile properties. These services are part of a service-oriented architecture (SOA), in which an application consists of one or more services provided on the server, and one or more clients.
Client applications for ASP.NET application services can be of different types and can run on different operating systems. These include these following types of clients:
- AJAX clients. These are ASP.NET Web pages (.aspx files) that run in the browser and that access application services from client script. AJAX clients typically use JSON format to exchange data. For more information, see Using Web Services in ASP.NET AJAX.
- .NET Framework clients. These are .NET Framework Windows applications that access application services over HTTP by using the provider model infrastructure, and that use JSON protocol to exchange data. For more information, see Client Application Services Overview.
- SOAP clients. These are clients that can access application services through SOAP 1.1. This is useful for clients that are running on other operating systems or using other technologies, such as Java applications. For more information, see Walkthrough: Using ASP.NET Application Services.
Hosting ASP.Net application Services in Azure is no different from hosting in on-premise server. The scenario that I've discussed in this blog is ASP.Net Client Application Services set-up and it's handling of cookies.
- Set up Membership Database in SQL Azure - https://support.microsoft.com/kb/2006191/
- Set up ASP.Net Application Services in Azure: Add/Edit the web.config (before deploying it to Azure) for the web role project to enable authentication and role service.
<connectionStrings>
<remove name="myConnection"/>
<add name="myConnection" connectionString="Server=tcp:blah.database.windows.net,1433;Database=ASPNetDatabase;User ID=user@blah;Password=blah;Trusted_Connection=False;Encrypt=True;" providerName="System.Data.SqlClient"/>
</connectionStrings>
<authentication mode="Forms">
<forms protection="Validation" cookieless="UseDeviceProfile" timeout="1" slidingExpiration="false" />
</authentication>
<roleManager enabled="true" defaultProvider="CustomSqlRoleProvider">
<providers>
<add name="CustomSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="myConnection" applicationName="myApplication" />
</providers>
</roleManager>
<membership defaultProvider="SqlMembershipProvider" hashAlgorithmType="SHA1">
<providers>
<add applicationName="myApplication" connectionStringName="myConnection"
enablePasswordReset="true" enablePasswordRetrieval="false" passwordFormat="Hashed"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="0" requiresQuestionAndAnswer="false"
requiresUniqueEmail="false" passwordAttemptWindow="5" passwordStrengthRegularExpression=""
name="SqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" />
</providers>
</membership>
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true"/>
<roleService enabled="true"/>
</webServices>
</scripting>
</system.web.extensions>
- Confiugre Client Application Services (Windows Forms Client) as per the MSDN documentation - https://msdn.microsoft.com/en-us/library/bb384312.aspx
- With the above three steps, you are all set to use the ASP.Net application services from a Windows Forms Client. Now comes the most interesting part, how do we handle authentication cookies in ClientApplicationServices? If it were ASP.Net client, when the cookie expires the application would automatically be redirected to the login page. There's no way windows forms application using client application services would have some functionality like that. However, there's a solution that exists and documented well on MSDN.
There are two steps to it, first make sure that cookie timeout is properly set in the forms element as shown below.
<authentication mode="Forms">
<forms protection="Validation" cookieless="UseDeviceProfile" timeout="1" slidingExpiration="false" />
</authentication>
Note: slidingExpiration should be set to false. Otherwise, for every successful login (like user validation) attempt by the user - last activity time and hence cookie time out gets reset. For more information, read MSDN documentation here.
The next step is to check for the cookie expiration and one of the ways to do it is to call GetRolesForUser for the logged in user. The key to this is that all the valid users should be assigned to roles. If no roles are returned, the login has expired. For more information, read MSDN documentation here.
Here's some sample code:
System.Security.Principal.IIdentity identity =
System.Threading.Thread.CurrentPrincipal.Identity;
// Return if the authentication type is not "ClientForms".
// This indicates that the user is logged out.
if (!identity.AuthenticationType.Equals("ClientForms")) return;
try
{
ClientRoleProvider provider =
(ClientRoleProvider)System.Web.Security.Roles.Provider;
String userName = identity.Name;
// Determine whether the user login has expired by attempting
// to retrieve roles from the service. Call the ResetCache method
// to ensure that the roles are retrieved from the service. If no
// roles are returned, then the login has expired. This assumes
// that every valid user has been assigned to one or more roles.
provider.ResetCache();
String[] roles = provider.GetRolesForUser(userName);
if (roles.Length == 0)
{
MessageBox.Show(
"Your login has expired. Please log in again to access " +
"the roles service.", "Attempting to access user roles...");
}
if (provider.IsUserInRole(userName, "Power Users"))
{
MessageBox.Show("User is still active");
}
}
catch (System.Net.WebException)
{
MessageBox.Show(
"Unable to access the remote service. " +
"Cannot retrieve user roles.", "Warning",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
Note: Some developers would try IsInRole method of the role service to check for expiration but it doesn't work always. The IsInRole method will always return false if the user login has expired. This will not occur if your application calls the IsInRole method one time shortly after authentication.
The sample project that I used is available for download!