Accessing ASP.NET Application Services from Silverlight (part 3)

See also part 1 and part 2.

So we're at the point where we've set up our environment, we've created a project structure and we've managed to call the membership service to authenticate users. What about if I want to make use of the (very useful) Profile store in ASP.NET. The Profile store allows me to maintain strongly typed data about users of my site that will be persisted for me automatically (typically a database such as SQL Server).

Imagine I have an existing site that makes use of profile data (in the case of my example a nickname and a shoe size), wouldn't it be useful if I could access that from a Silverlight page that I added to my site? Does the Pope live in the woods?

In my web.config I have my profile properties defined thus (in <system.web> ):

 <profile>
  <properties>
    <add name="NickName" type="System.String" />
    <add name="ShoeSize" type="System.Int32" defaultValue="12" />
  </properties>
</profile>

And in <system.web.extensions> I enable the Profile service for ASP.NET AJAX with:

 <system.web.extensions>
  <scripting>
    <webServices>
      <authenticationService enabled="true" requireSSL="false"  />
      
      <profileService enabled="true" 
                      readAccessProperties="NickName,ShoeSize" />

      <!-- Uncomment this section to enable the role service.
          <roleService enabled="true"/> -->
    </webServices>
  </scripting>
</system.web.extensions>

I create a class (UserProperties) of the right shape so that the profile properties can be deserialised into an instance of this class. I create a private field in my Page class to maintain the user properties.

 private UserProperties up;
 public class UserProperties
{
  private string nickName;
  private int shoeSize;

  public string NickName
  {
    get { return nickName; }
    set { nickName = value; }
  }

  public int ShoeSize
  {
    get { return shoeSize; }
    set { shoeSize = value; }
  }
}

Now we can setup the call to get the user properties in much the same way as we did when calling the membership service in Part 2 except this time we'll do it asynchronously. I create my BrowserHttpWebRequest object by calling the CreateApplicationServiceRequest() helper method I created in Part 2 but this time passing the PropertiesServiceMethod string ("Profile_JSON_AppService.axd/GetAllPropertiesForCurrentUser"). This time I want to to pass a parameter so again I create a helper class to store the parameter(s) to be serialised into the request stream (see below further down for the RequestParameters class definition).

 private void GetUserProfileProperties()
{
  BrowserHttpWebRequest profileRequest =
    CreateNewApplicationServiceRequest(PropertiesServiceMethod);

  StreamWriter sw = new StreamWriter(profileRequest.GetRequestStream());
  JavaScriptSerializer j_ser = new JavaScriptSerializer();

  RequestParameters rp = new RequestParameters() { authenticatedUserOnly = false };
  sw.Write(j_ser.Serialize(rp));
  sw.Flush();
  profileRequest.BeginGetResponse(new AsyncCallback(HandleResponse), profileRequest);
  sw.Close();
}

The RequestParamaters object is serialised and written to the request stream and we initiate the web service call with profileRequest.BeginGetResponse() passing in the callback method and our profileRequest object as state. In the HandleResponse() method we recover our profileRequest object from the AsyncState on the IAsyncResult object passed to us as a parameter in the callback. A call to profileRequest.EndGetResponse() gets us the HttpWebResponse from which we can deserialise the user properties from the response stream.

 private void HandleResponse(IAsyncResult ar)
{
  BrowserHttpWebRequest profileRequest = ar.AsyncState as BrowserHttpWebRequest;

  HttpWebResponse response = profileRequest.EndGetResponse(ar);
  StreamReader responseReader = new StreamReader(response.GetResponseStream());
  string rawResponse = responseReader.ReadToEnd();
  responseReader.Close();
  response.Close();
  JavaScriptSerializer j_ser = new JavaScriptSerializer();
  up = j_ser.Deserialize<UserProperties>(rawResponse);
}

On the page I make a call the GetUserProfileProperties() on Page.Loaded and after a call to ExecuteLogin() to ensure the latest profile properties are available. Below is the definition for the RequestParameters helper class.

 public class RequestParameters
{
  private bool _authenticatedUserOnly;

  public bool authenticatedUserOnly
  {
    get { return _authenticatedUserOnly; }
    set { _authenticatedUserOnly = value; }
  }
}

There are other variations on the membership and authentication service methods available to you - the best thing to do is refer to the Sys.Services namespace documentation for ASP.NET AJAX and make sure you have Fiddler (or a similar tool) to hand.

I understand that Silverlight projects will be able to use the new Client Application Services functionality in Visual Studio 2008. In which case, all this reduces to checking the "Enable client application services" checkbox in the Services dialogue... :-)

image

Technorati tags: silverlight, asp.net ajax, profile