in

ASP.NET Weblogs

A Recipe for New Media

September 2007 - Posts

  • AJAX and Authentication and Profile Services

    Still working on our company website, today I decided to try out the Authentication and Profile Services that are part of the ASP.NET AJAX Extensions.  Basically (for those who don't know) the Authentication and Profile Services are a set of Javascript classes (Sys.Services.AuthenticationService and Sys.Services.ProfileService respectively) and some built in web services that are part of the extensions, that allow you to log in with actually have to refresh the page or redirect to a new page (and logout as well, but it redirects and/or refreshes the page after it asynchronously logs out) and access ASP.NET Profile properties (both read and write, more on that in a minute).  So basically these services allow you to not have to reload pages to access information and manage your logged in state, which means faster response times and smoother user experiences.

    So let's look at how we go about doing this.  I will assume that you have started from an already existing ASP.NET AJAX-enabled website.  (If not, just start Visual Studio 2005 and select ASP.NET AJAX-Enabled Web Site, if you don't see that option, you probably don't have the ASP.NET AJAX Extensions installed, go here to get them).  You will also have to configure your website to use ASP.NET Authentication (I'm not going to cover that here, but you can go here for a good tutorial on Membership, Roles and Profiles (including authentication)).

    Ok, let's begin.  The first thing you need to do is turn on the services.  In your web.config you will find a configuration section called <system.web.extensions> (you can actually search for that, including the brackets.) and within that section you will find two lines <authenticationService enabled="true" requireSSL="true|false"/> and <profileService enabled="true" readAccessProperties="" writeAccessProperties="" />.  They are currently commented out.  Uncomment them.  The next thing you need to do is decide if you want to force your site to have to use SSL for the authentication process (to protect the username and password), if you can use SSL then go ahead and put true in requireSSL, otherwise put false.  The next step is decide what properties you want to expose via the profileService.  Let me explain this part in a bit more detail.

    This is how my profile is defined:

    <profile enabled="true">
          <properties>
            <group name="Address">
              <add name="Street1" type="string"/>
              <add name="Street2" type="string"/>
              <add name="City" type="string"/>
              <add name="Province" type="string"/>
              <add name="Postal" type="string"/>
              <add name="Country" type="string"/>
            </group>
            <group name="Contact">
              <add name="Name" type="string"/>
              <add name="Title" type="string"/>
              <add name="Phone" type="string"/>
              <add name="Cell" type="string"/>
              <add name="Fax" type="string"/>
              <add name="Website" type="string"/>
            </group>
            <add name="CompanyName" type="string"/>
          </properties>
        </profile>

    So I decided that I wanted to be able to expose the Contact Name and the Company Name, so I wrote my readAccessProperties attribute like so readAccessProperties="Contact.Name,CompanyName". Notice how I accessed a property group by using dot notation (Contact as you can see above is a property group and Name is a property in the property group).  In code, I would access the property via [Page].Profile.Contact.Name.  If you want to give write access to Profile properties then place their names in the writeAccessProperties attribute.

    The next step is setting up authentication in the page.  The first thing I did was put two input boxes on the page and called one username and the other password.  Then I placed a button on the form that when clicked would fire a javascript event called Login.

    <table id="LoginBox">
        <tr>
            <td>Username: <input type="text" id="username" /></td>
            <td>Password: <input type="text" id="password" /></td>
            <td><input type="button" value="Log in" onclick="Login()" /></td>
        </tr>
    </table>

    The next step is writing the login function:

    var uid = $get("username").value;var pwd = $get("password").value;
    Sys.Services.AuthenticationService.login(uid,pwd,false,null,null,OnLoginCompleted,OnCommunicationFailed, null);

    Now we need to write the functions that handle if the login call was successful (not if logging in was successful, that's handled later) or not.

    function OnLoginCompleted(isValid,userContext, methodName) {
        if (isValid) {
            LoadProfile(userContext);
            }
        else {
            alert("Login failed.");
        }
    }

    function OnCommunicationFailed(error, userContext, methodName){    alert("Attempt failed: " + error.get_message());}

    Obviously, you can make these functions much more "elegant", but these will do for now.  At this point (apart from the LoadProfile method call), you can log someone in and handle a successful login or a bad username/password.  And if there is a communication failure with the server, it will call OnCommunicationFailed.  Logging someone out is as simple as calling Sys.Services.AuthenticationService.logout(null, null, OnCommunicationFailed, null);  If you want to redirect the user to a new page upon successful logout, then replace the first null with the location path.  If you leave it as null it will refresh the page upon successful logout.

    Profile Service

    Now we will look at the profile service, which in my example is where the LoadProfile method call from the Authentication example above comes in.  And here it is:

    function LoadProfile(){
        Sys.Services.ProfileService.load(null, OnProfileLoadCompleted, OnProfileFailed, null); 
    }

    It is farily sipmlye call.  What it does is call in the AJAX Extensions embedded web service to retrieve the profile properties that were specified in the web.config file.  How these properties are accessed can be seen in the OnProfileLoadCompleted method:

    function OnProfileLoadCompleted(numProperties, userContext, methodName){
        $get("LoginBox").style.display = "none";
        welcomeBox.innerHTML = "Welcome " + Sys.Services.ProfileService.properties.Contact.Name + "<input type='button' value='logout' onclick='LogOut()'>";   
       
    __doPostBack('UpdatePanel1', '');
    }

    As you can see it is very easy to access profile properties as they simply become part of the properties property on the ProfileService object (the second line of the function).  Remember though that only the profile properties you specify in the web.config get exposed.  The first line of the method above hides the login box.  The second line replaces the login box with a welcome message that is personalized with the user's full name.  The last line is interesting though.  Once you are logged in, you want to display content that is specific to being logged in.  How I did that in the website is refresh an AJAX UpdatePanel and that is what this line does.  The Postback functionality of ASP.NET gets "hijacked" by the AJAX Extensions so that if an Async trigger (the UpdatePanel Trigger collection defines these) or an UpdatePanel is the target of the Postback, it stops the regular post back and performs an Async callback and reloads the specified UpdatePanel.

    And that is basically my experience with Authentication and Profile Services within the AJAX Extensions.  Simple, but powerful.

  • AJAX, Flash CS3, and Dynamic Javascript

    Well, I've been having some fun with AJAX and Flash CS3.  Here is the scenario:

    I had 4 pages that were all the same basically except for a block of text.  Each of these pages had icons indicating short video clips (usually 4 per page).  When you clicked these icons, the screen would grey out and a picture of a flat screen TV would come up over the web page and play the video, you could click on the OK button and the video would stop, the TV go away and the web page would go back to normal.

     How I accomplished this was simply in the execution, but complex in the JavaScript :-)  I simply used the ModalPopupExtender from the AJAX Control Toolkit to grey out the screen and popup the TV (which was simply a picture).  In the middle of the TV, I put a Flash object to play the video.  When you clicked the icon, two events were fired.  The first one showed the Modal Popup, the second event sent a message via Flash's ExternalInterface to the Flash file telling it which video to play.  When you clicked the button to close the Modal window, it sent another message to flash (again via the ExternalInterface in flash) to stop playing the video.  This way, I didn't have to keep recreating / reloading the Flash file, it simply stayed in the page and starting the video was a fast and seemless process, until I tried to use AJAX, that is.

    Like I said, the pages were the same except for a block of text and which videos the icons played.  Being that the pages are graphically heavy and take 3-6 seconds to load to begin with, I figured it was a good candidate for AJAX, and it was.  The load time for page changes went down to 1-2 seconds.  I was quite pleased with myself, I clicked one of the icons, and the ModalPopup worked!!  ... but the TV screen was "blank", there was a big hole where the Flash player should have been and Javascript was throwing errors.

     The issue was this:  When you update a block of text via AJAX that has embedded script tags, the script doesn't run.  The way around this is to use the static methods on the ScriptManager class, specifically RegisterClientScriptBlock.  The problem with that is that script that Flash CS3 generates to get around the "Click or press spacebar" message relies on inlining the script in the page.  (Not the whole script, you make a method call to the function that produces the tags, but it does a document.write to insert the result at the point in the webpage where it was called).  So I opened up the Javascript file, found the point in the code where it did the document.write and added a bit of code to replace the innerHTML of a target span (that could be specified as part of the list of parameters to the method).  I then placed a span where I wanted the video to appear.  I could have gotten around this by placing the asp:Panel that made up the TV outside of the UpdatePanel and it would have worked as is, but that would be too easy :-)  Actually, I needed to clear the video between pages (the Audio demos page would end up with the last frame from the previous video showing as the audio demos are audio, not video, and flash has a glitch in it that I could not clear the last frame from the previous video without without running a new video or reloading the page). 

    It may not sound like much.  But if you are not used to working with the strangeness that is embedded Javascript and AJAX UpdatePanels (not to mention that Flash itself is a little goofy).  Actually, let me explain that statement.  There is an issue in Flash CS3 where under Internet Explorer, the variable used to reference the Flash object doesn't get assigned (it has to do with the fact that when you create an element with an ID within a form, instead of creating a reference to it in the window object (ie.  window.NewPortfolio), it creates it within the form only (ie. document.forms[0].NewPortfolio)).  In my webpage, the Flash file is called NewPortfolio.swf, so I use an ID of NewPortfolio for the Flash object.  You need to know this ID name because you access the Flash ExternalInterface's methods by simply (in this case) saying NewPortfolio.playVideo([path to swf]), very much like PageMethods in AJAX Extensions.  So if the variable didn't get created in the correct place (on the window object), you get a ton of Javascript errors.  The way around this is right after you make the call to the Javascript that Adobe provides for inserting the Flash object, write a line like this:

    NewPortfolio = document.NewPortfolio

    And everything goes back to working the way it's supposed to.  (To make matters even more weird, under certain circumstances you have to write "<form></form>" right inside your <form runat="server"> tag to make Flash work right as well.  I've managed to get around that by rewriting some of my HTML (what precisely I did, I can't remember.  That "fix" was several months ago) and as outlined above.  So I think that Adobe should really look at fixing this problem before in the next release of Flash (or maybe it's Microsoft's "problem", I never know who to blame :-)

    For more information see:
    ScriptManager.RegisterClientScriptBlock
    The Oddness of IE / Flash

  • Let me introduce myself

    Good day ladies and gentlemen.  Welcome to today's meeting of Programmers Anonymous where we seek to help those who are addicted to programming.  My name is Adam Greene, and I am a programmer.  Hello Adam. 

    Doesn't it feel at times like we like our work a little too much??  Maybe we are addicted to programming?  I'm not sure, but I know I'm really digging ASP.NET and all the other cool Microsoft technologies.

    Let me back up for a minute and introduce myself.  My name is Adam Greene (which you already know), and I am the Lead Developer at Trimedia Atlantic Inc (which you probably didn't know).  Trimedia does everything from Video and Audio for television to Print management.  Basically we are a marketing company without the marketing part :-)  My job here is to help move our clients from traditional medias to "New Media".  What is new media, you ask?  Good question.  It is really just a buzz word.  It means "take what you have always done and do it in a new way / medium".  For us, it means moving our clients away from normal websites to what we call "Advanced Web Systems".  Our goal is to help our clients leverage their websites to increase their customer interaction, retention, and satisfaction through Web 2.0 technologies and Rich Internet Experience technologies.  Our technology of choice to that end is Microsoft ASP.NET, Silverlight, and Windows Presentation Framework.  Basically all things Microsoft.

    The purpose of this blog will be to catalog my adventures in New Media and how we apply Microsoft technologies to our day to day development challenges.  I will also talk about Web 2.0 technologies in general, which will mean at times I will be talking about, dare I say it .... non-Microsoft technologies.  The reason for this is that my other day job is "Media Programming Instructor" at McKenzie College.  In the Media Programming course we will be teaching the students how to develop web games from start to finish in Flash CS3 / ActionScript 3.0 (along with basic E-Commerce, you can't make a penny at web games unless you have a website to put them in).  We will also be teaching them PHP and MySQL (I know, I know.  I tried to get them to teach MSSQL and ASP.NET, but being an "arts" college, they use Apple computers and are an Adobe licensed training center).  If someone offered to give them the same deal (hint, hint) on Intel / Microsoft, I'm sure I could convince them to go for it.

More Posts