Windows Live Development Part 1 - Authenticating users via Windows Live ID

June 20, 2008 00:01 by MartinHN

With so many online services out there, you nearly claim a new online identity somewhere every day. You tend to use the same username and password couple for all of them, but sometimes your preferred username is taken, or your password does not meet the sites' password policy. I reckon I have well over 100 online identities out there - I rely on the same 3-4 combinations of username and password, and it's really messy. In this blog post I'm going to cover how to authenticate users of an ASP.NET application against Windows Live, using the SDK for Windows Live ID. I'm going use the built-in ASP.NET Membership mechanism and go from there.

I could have gone the OpenID way, but Scott Hanselman already did an example on OpenID, so I thought I'd try out Windows Live. Jeff Atwood asked the question, if we really need another username and password in the pursuit of the best authentication model for stackoverflow.com.

Conceptual idea of using Windows Live ID

tmpF3A8Windows Live ID, is the technology you should be quite familiar with when authenticating on Microsoft web sites, and Messenger. If you want to know more about what Windows Live ID is, take a look at this video from Channel9.

When using Windows Live ID, you redirect the user to the Windows Live login-page, with a return URL specified. When the user authenticates, Windows Live will redirect the user back to your site, and delivering a user id and a token. Here's an overview of how it looks:

image

Getting your application ID to use Windows Live ID

To get started using Windows Live ID, first of all you need an application ID. Basically you need to sign up for one, and register your application. Go to https://msm.live.com/app/default.aspx and click 'Register an Application'. (You can find Microsoft's guide to this here: http://msdn.microsoft.com/en-us/library/cc287659.aspx)

tmpF3F5

Leave Domain Name blank. Save your self-chosen Secret Key for later use, and submit the form. When you see the confirmation page, your application ID is shown. Copy that, as we're going to use it later.

In the return URL field, type the URL of your application followed by a name of a page to handle the Windows Live ID communication, like http://localhost/demoapp/webauth-handler.aspx.

Download and install Windows Live ID Web Authentication SDK

Microsoft has made it quite easy for ASP.NET developers to get started, by providing an SDK. Download it here: http://www.microsoft.com/downloads/details.aspx?FamilyId=24195B4E-6335-4844-A71D-7D395D20E67B&displaylang=en and install the SDK. By default it is installed here: C:\Program Files\Windows Live ID\WebAuth

From the SDK we need a class called WindowsLiveLogin, located in the App_Code folder of the sample. Keep this file in mind for a few seconds.

Start coding - create a new website

Open Visual Studio 2005/2008 and create a new ASP.NET website the way you want it. First we will add the WindowsLiveLogin.cs file to our App_Code folder. (C:\Program Files\Windows Live ID\WebAuth\Sample\App_Code\WindowsLiveLogin.cs).

Leave the default.aspx page, and put the following HTML in the markup:

<html>
<head>
  <title>Windows Live&trade; ID</title>
</head>
<body>
  <iframe id="WebAuthControl" name="WebAuthControl" src="http://login.live.com/controls/WebAuth.htm?appid=<%=AppId%>&style=font-size%3A+10pt%3B+font-family%3A+verdana%3B+background%3A+white%3B"
    width="80px" height="20px" marginwidth="0" marginheight="0" align="middle" frameborder="0"
    scrolling="no"></iframe>
  <%
   1:  if (UserId == null)
   2:      { 
%> <p> This application does not know who you are! Click the <b>Sign in</b> link above.</p> <%
   1:  }
   2:      else
   3:      { 
%> <p> Now this application knows that you are the user with ID = "<b><%
   1: =UserId
%></b>".</p> <%
   1:  } 
%> </body> </html>

And this piece of code in its code-behind class.

using System;
using System.Web;
using System.IO;
using WindowsLive;

public partial class DefaultPage : System.Web.UI.Page
{
  const string LoginCookie = "webauthtoken";

  // Initialize the WindowsLiveLogin class.
  private static WindowsLiveLogin wll = new WindowsLiveLogin(true);
  
  protected static string AppId = wll.AppId;
  protected string UserId;

  protected void Page_Load(object sender, EventArgs e)
  {
    HttpRequest req = HttpContext.Current.Request;
    HttpApplicationState app = HttpContext.Current.Application;

    HttpCookie loginCookie = req.Cookies[LoginCookie];

    if (loginCookie != null)
    {
      string token = loginCookie.Value;

      WindowsLiveLogin.User user = wll.ProcessToken(token);

      if (user != null)
      {
        UserId = user.Id;
      }
    }
  }
}

Default.aspx will work as a login page. Users click the Sign-in button, and is redirected to Windows Live. When they authenticate, they're redirected back to our handler page, that we will now create...

Create a new aspx page, and name it webauth-handler.aspx. Recall that this was the page we provided as the return URL when we registered the application at Windows Live.

This page will serve as the handler page for the user, when Windows Live redirects back to your site. Windows Live will post authentication specific values for you to use. Because this page is never seen by a user (we will send the user back where they began), we can simply remove all the markup.

Put the following code in your code-behind class for webauth-handler.aspx.

using System;
using System.Web;
using System.IO;
using WindowsLive;

public partial class HandlerPage : System.Web.UI.Page
{
  // Relative path to the login- and logoutpage.
  const string LoginPage = "default.aspx";
  const string LogoutPage = "default.aspx";
  const string LoginCookie = "webauthtoken";
  static DateTime ExpireCookie = DateTime.Now.AddYears(-10);
  static DateTime PersistCookie = DateTime.Now.AddYears(10);

  // Initialize the WindowsLiveLogin class.
  static WindowsLiveLogin wll = new WindowsLiveLogin(true);

  protected void Page_Load(object sender, EventArgs e)
  {
    HttpRequest request = HttpContext.Current.Request;
    HttpResponse response = HttpContext.Current.Response;
    HttpApplicationState application = HttpContext.Current.Application;

    string action = request["action"];

    if (action == "logout")
    {
      HttpCookie loginCookie = new HttpCookie(LoginCookie);
      loginCookie.Expires = ExpireCookie;
      response.Cookies.Add(loginCookie);
      response.Redirect(LogoutPage);
      response.End();
    }
    else if (action == "clearcookie")
    {
      HttpCookie loginCookie = new HttpCookie(LoginCookie);
      loginCookie.Expires = ExpireCookie;
      response.Cookies.Add(loginCookie);

      string type;
      byte[] content;
      wll.GetClearCookieResponse(out type, out content);
      response.ContentType = type;
      response.OutputStream.Write(content, 0, content.Length);

      response.End();
    }
    else if (action == "login")
    {
      HttpCookie loginCookie = new HttpCookie(LoginCookie);

      WindowsLiveLogin.User user = wll.ProcessLogin(request.Form);

      if (user != null)
      {
        loginCookie.Value = user.Token;

        if (user.UsePersistentCookie)
        {
          loginCookie.Expires = PersistCookie;
        }
      }
      else
      {
        loginCookie.Expires = ExpireCookie;
      }

      response.Cookies.Add(loginCookie);
      response.Redirect(LoginPage);
      response.End();
    }
    else
    {
      response.Redirect(LoginPage);
      response.End();
    }
  }
}

The first login test

Now we've got everything setup as we should, and it should be possible to login using Windows Live. View the default.aspx page in your favorite browser, and let's try.

First you will see out login page:
tmp9D6

Click the Sign in link, which will take you to Windows Live:
wlive_signin

Sign in with your Windows Live ID, and you will return to our login page - which will now welcome you and show your user ID:
wlive_signin 

Now your user has authenticated against Windows Live, using the Windows Live ID. Now it's up to you to handle the user's Windows Live ID, which is what I'm going to blog about in part 2 of the Windows Live Development series here...


kick it on DotNetKicks.com

Currently rated 4.3 by 3 people

  • Currently 4.333333/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Add to: Facebook Add to: Digg Add to: Del.icio.us Add to: Reddit Add to: Furl Add to: Yahoo Add to: Spurl Add to: Google Add to: Technorati

ASP.NET Server Control: FeedList - List most recent items from an RSS feed as links

April 21, 2008 22:30 by MartinHN

RSS feeds is everywhere, and rightly so. Just about any modern browser, e-mail client, search engine or mobile phone is compliant with the RSS technology, and it gives web developers an easy and very convenient way to share and consume content across the web. From time to time I need to show a list of recent items form an RSS feed. This is a very easy thing to do, and I always end up copying the same usercontrol around, which becomes nothing but a mess! Eventually I need to change a few things, which means I get different versions of the same control spread throughout my projects.

This mess has got to stop, and from now on I'll put all my common controls in a class library project, which I can reference from all the other projects.

Back to my RSS feed reader - this is the first control I've made into a server control, from one of my many usercontrols around the projects folder. The control downloads the XML at the Url of the RSS feed, and renders a list of links. The controls contains a few properties:

  • FeedUrl: The Url of the RSS feed to download
  • NumberOfItems: The number of items which should be rendered. Defaults to 5 if none is specified.
  • CssClass (Part of the WebControl class, from which FeedList derives): Use this so you have style the control from CSS.

The code

It really is straight forward. Below is the method that renders the links.

private void RenderFeedItems(HtmlTextWriter writer)
{
  if (!String.IsNullOrEmpty(FeedUrl))
  {
    XmlDocument doc = new XmlDocument();
    doc.Load(FeedUrl);

    XmlNodeList items = doc.DocumentElement.SelectNodes("channel/item");

    if (items != null)
    {
      int bounce = NumberOfItems;
      if (items.Count < NumberOfItems)
        bounce = items.Count;

      for (int i = 0; i < bounce; i++)
      {
        XmlNode titleNode = items[i].SelectSingleNode("title");
        XmlNode urlNode = items[i].SelectSingleNode("link");
        XmlNode pubDateNode = items[i].SelectSingleNode("pubDate");

        string title = String.Empty;
        string url = String.Empty;
        DateTime pubDate = new DateTime();

        if (titleNode != null)
          title = titleNode.InnerText;

        if (urlNode != null)
          url = urlNode.InnerText;

        if (pubDateNode != null)
          DateTime.TryParse(pubDateNode.InnerText, out pubDate);

        writer.RenderBeginTag(HtmlTextWriterTag.Li);

        writer.AddAttribute(HtmlTextWriterAttribute.Href, url);
        writer.AddAttribute(HtmlTextWriterAttribute.Title, title);
        writer.RenderBeginTag(HtmlTextWriterTag.A);
        writer.Write(title);
        writer.RenderEndTag();

        writer.RenderEndTag();
      }
    }
    else
    {
      RenderErrorMessage(writer, String.Format("No RSS-feed items found at: {0}", FeedUrl));
    }
  }
  else
  {
    throw new Exception("FeedUrl cannot be empty!");
  }
}

To use the control, put it in your website's App_Code folder, and add the following to the <controls> collection of your <pages> section in web.config:

<add tagPrefix="dnknormark" namespace="dnknormark" />

This should make your <pages> section look like this one:

<pages>
  <controls>
    <add tagPrefix="dnknormark" namespace="dnknormark" />
  </controls>
</pages>
 
And to put it on an aspx page, and show the latest 5 items from this blog, add this line to the page:
 
<dnknormark:FeedList ID="lstFeeds" runat="server" CssClass="feedList" 
NumberOfItems="5" FeedUrl="http://www.dnknormark.net/syndication.axd" />

Use it as you'd like. Feel free to change it, the way you need.


kick it on DotNetKicks.com


Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Add to: Facebook Add to: Digg Add to: Del.icio.us Add to: Reddit Add to: Furl Add to: Yahoo Add to: Spurl Add to: Google Add to: Technorati

Event performance optimization with the EventHandlerList

December 25, 2007 23:35 by MartinHN

When using custom events (event delegates) in your ASP.NET pages, user controls and server controls, many developers might define their Events as public fields, like this:

public event EventHandler<EventArgs> MyCustomEvent;


And use this code to fire the event:

protected void OnMyCustomEvent(EventArgs e)
{
  if(MyCustomEvent != null)
  {
    MyCustomEvent(this, e);
  }
}

 

Nothing is wrong with the approach of the latter, but defining the MyCustomEvent as a public field introduces two problems:

    1. Even though no clients have registered any delegates to the invocation list of your event, the compiler generates
      one private delegate field for each event delegate in your class. This is a waste of server memory, especially if
      you have several events inside your class.

    2. One Add and one Remove method is generated for each event field of your class. When clients use += and -= to add
      and remove delegates from the invocation lists of your class' events, these methods are called behind the scenes.
      These two compiler-generated methods are thread-safe, which means they include extra code to synchronize threads
      that are accessing these methods. This means, that everytime a client adds or removes a delegate to or from the
      invocation list of an event, they have to get a lock before they can do the actual work. This introduces an
      unnecessary overhead because most page developers don’t use multiple threads and therefore there is no need for
      thread synchronization.

     

    The EventHandlerList is the answer to our issues. This class comes with the .NET Framework. The EventHandlerList is a linked list of delegates,which is optimized for adding and removing delegates. To use the EventHandlerList in your classes, you need to add a private static key for each event your class exposes. The code bellow defines a key for MyCustomEvent:

    private static readonly object MyCustomEventKey = new object();

    The memory is allocated only once, because the key is static.

    After this, you need to define your events as properties - not fields. These event properties has a different syntax that normal get-set properties. Event properties uses add-remove instead of get-set. The following property, is an event property for MyCustomEvent:

    public event EventHandler<EventArgs> MyCustomEvent
    {
      add { Events.AddHandler(MyCustomEventKey, value); }
      remove { Events.RemoveHandler(MyCustomEventKey, value); }
    }
     

    Every Page, UserControl and WebControl - among others - has a protected property of type EventHandlerList named Events. With this approach, when clients use += to add a delegate to the invocation list of the MyCustomEvent, the add method of the event property calls the AddHandler method of the EventHanderList class, as the code above will tell you. As for -= the RemoveHandler method is called.

    The EventHandlerList class maintains a linked list which can have none or one entry for each event. The AddHandler method checks whether this internal linked list contains an entry for an event with the given event key. If it does, the method calls the Combine method of the Delegate class to add the client delegate to the invocation list of the event. If this internal list doesn’t contain an entry for an event with the given event key, the AddHandler method just adds a new entry.

    With this new approach, we need to update our OnMyCustomEvent Method, which is responsible for firing the event:

    protected void OnMyCustomEvent(EventArgs e)
    {
      EventHandler<EventArgs> handler = Events[MyCustomEventKey] as EventHandler<EventArgs>;
    
      if (handler != null)
        handler(this, e);
    }
     

    This method uses the MyCustomEventKey as an index in the Events list to access the MyCustomEvent-event. The Events list will return null if it does not contain an entry at the specified index. This will happen when no clients has subscribed to the MyCustomEvent.

    Using the EventHandlerList class automatically resolves the two previously mentioned performance problems with the event fields.

    Technorati Tags: ,

     

    kick it on DotNetKicks.com

    Currently rated 5.0 by 1 people

    • Currently 5/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    Add to: Facebook Add to: Digg Add to: Del.icio.us Add to: Reddit Add to: Furl Add to: Yahoo Add to: Spurl Add to: Google Add to: Technorati

    Configuring IIS 7 default document from web.config

    December 20, 2007 21:14 by MartinHN

    IIS 7 has a lot of changes regarding the configuration model. Using the Integrated Configuration System in IIS 7 you can set configuration of your server on different levels, compared to IIS 6, where the ASP.NET developer were more restricted. Configuring IIS 7 from an ASP.NET Web Application's web.config file works from both ASP.NET 2.0 and ASP.NET 3.5. Note that the server can be restricted to lock certain configuration settings from above the application level, you might encounter this if your website runs in a shared hosting environment.

    Setting up the website

    To have a test website, I will setup a new website on my Vista machine running IIS 7. I don't want the website to run under the Default Web Site, so first thing, I'll add a hostname to my hosts file. This is located in the drivers\etc folder of your windows directory's system32 folder. Add the following line:

    127.0.0.1         iis7test

    Open up Internet Information Services (IIS) Manager, and create a new Application Pool. Name it iis7test, and leave the settings as default:

    image

    Add a new website with the following settings:

    image

    This should get us started. Open up Visual Studio 2008 (2005 will also work). Open the website you just created inside IIS.

    image

    The only item in the website is a web.config. Add a new Web Form called Test.aspx.

    Right-click the Test.aspx file and click View in browser. You could get an HTTP Error 500.00, like this:

    image

    To get rid of it, set impersonate to false in the web.config file by adding this line to the system.web section:

    <identity impersonate="false" />

    Now your site should work fine. Edit the Test.aspx file, so it has some content. Just write Test IIS 7 or something in the HTML mark-up.

    If you right-click the website icon in the Solution Explorer, and click View in browser, you will get an error like the one bellow:

    image

    That is because our website does not have any pages that match the name of the default documents on IIS. If you don't want to be limited by the few default documents that comes with IIS out-of-the-box, you can add your own from web.config by adding these lines:

    <system.webServer>
        <defaultDocument>
            <files>
                <clear />
                <add value="Test.aspx" />
            </files>
        </defaultDocument>
    </system.webServer>       

     

    Maybe the system.webServer section already existed in your web.config file. If so, just add the defaultDocument section. Here you can specify all the filenames that should act as a default document in IIS 7. The <clear /> line is optional. If you want to keep the default settings, and only add your own - just delete that line.

    Now when we save the new web.config file, and refresh the browser we se our Test.aspx file:

    image

    This setting is just one of many that you can specify in your application's web.config file. In the near future I'll be blogging more about specific settings you can use to configure IIS 7 from ASP.NET.

    Technorati Tags: ,

    kick it on DotNetKicks.com

    Currently rated 5.0 by 2 people

    • Currently 5/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    Add to: Facebook Add to: Digg Add to: Del.icio.us Add to: Reddit Add to: Furl Add to: Yahoo Add to: Spurl Add to: Google Add to: Technorati
    Tags: ,
    Categories: ASP.NET | IIS7
    Actions: E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed

    Sending e-mails from your ASP.NET app and maintaining a list of recipients

    December 18, 2007 21:05 by MartinHN

    Making your application send e-mails, is something you do almost in every application. It's easy - all you need is an SMTP server to relay your mail through. Sending e-mail messages to several recipients at once can also be done, by adding multiple recipients to either of the MailMessage.To, MailMessage.Cc or MailMessage.Bcc properties in C#. But if you send a newsletter every month, week or day, it is very important to maintain your list of recipients, so that whenever people get a new e-mail address (and they do!) and the old one stop working - you avoid those undelivered mails everytime you send your newsletter.

    I've made this simple class called BulkSender, that takes three parameters in the constructor:
    mailMessage (System.Net.Mail.MailMessage), recipients (List<string>), mailSender (System.Net.Mail.SmtpClient).

    It has one method: SendEmailMessage, and what it does is, that it adds all recipients to the Bcc collection on the MailMessage, and sends the mail in a try-catch block. Whenever the SmtpFailedRecipientsException or SmtpFailedRecipientException is handled, it adds the e-mail address to a local List<string> and returns the e-mail addresses with delivery failures as a List<string>.

    Code snippet:
    image

    When you get the List<string> of failed recipients, you can add your own logic to take care of maintaining your list of recipients. Maybe an e-mail address has to fail 3 times, before it is deleted, or maybe you want to delete it the first time it fails.

    Another good thing to have in mind when sending e-mails to multiple recipients at once, is to add the mail addresses to the Bcc collection, and NOT the To or Cc collection. This way the e-mail addresses is hidden, you only get to see 'undisclosed-recipients' in you mail client:
    image 

    Note that the BulkSender class automatically clears the To, Cc and Bcc collections before adding the recipients to the Bcc collection. This way you know for sure, that you do not have any e-mail addresses publicly available when you send the e-mail.

    You can download the code below. Feel free to tweak the class - and let me know if you have some interesting things regarding this topic.

    Technorati Tags: ,

    BulkSender.zip (818.00 bytes)


    kick it on DotNetKicks.com

    Be the first to rate this post

    • Currently 0/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    Add to: Facebook Add to: Digg Add to: Del.icio.us Add to: Reddit Add to: Furl Add to: Yahoo Add to: Spurl Add to: Google Add to: Technorati
    Tags: ,
    Categories: .NET | ASP.NET | C#
    Actions: E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed

    How to handle IIS Event id 1009 (Event id 5011 on IIS 7)

    October 26, 2007 18:57 by MartinHN

    Recently at work we had some serious production environment issues. Our web application basically made the IIS application pool terminate unexpectedly. And we didn't get a single stack trace or a line of code. The only thing that was logged inside of the Windows Event Viewer, was event id 1009, which basically told that the application pool serving our app terminated unexpectedly. And that was it. All active user sessions were wiped, and the users had to login again.

    The error started after we did a major upgrade. A lot of our code had changed since the previous version, so we set up an new website and application pool inside IIS 6.0 for the new version, so we could upload the new application, and then turn off the old one, to get as seamless an upgrade as possible. It worked fine, and we were happy. Until a few hours later, when we saw our users were logged off.

    At first we thought it was IIS settings we had done wrong, so we did a complete comparison with the old website and application pool to see if we forgot anything. There was no difference at all. After a while, we realized that the only thing that could make the IIS crash like that, was our own code. But with no clue of where the danger in our code were - we were lost.

    After some time, we got WinDbg attached to the worker process of IIS, serving our application. We caught a few memory dumps, but those were not of the exception we were looking for.

    Later I found an HttpModule for ASP.NET. Basically the .Net framework 2.0 has changed the way it handles exceptions from other threads in IIS. In ASP.NET 1.1, unhandled exceptions from asynchronous threads inside IIS were ignored. But in ASP.NET 2.0, those unhandled exceptions makes the IIS application pool crash.

    Make the IIS crash yourself

    So try to do this. Create a new ASP.NET 2.0 website running on your local IIS. You only need a single page, so you're fine with the default.aspx Visual Studio creates for you. Add a button to the page, and create an event handler for the buttons OnClick event.

    Add this to your code-behind:

      /// <summary>
      /// Handles the Click event of the btnMakeCrash control.
      /// </summary>
      /// <param name="sender">The source of the event.</param>
      /// <param name="e">The EventArgs instance containing the event data.</param>
      protected void btnMakeCrash_Click(object sender, EventArgs e)
      {
        ThreadPool.QueueUserWorkItem(new WaitCallback(MakeIisCrash));
      }
    
      /// <summary>
      /// Makes the IIS crash.
      /// </summary>
      /// <param name="stateInfo">The state info.</param>
      private void MakeIisCrash(object stateInfo)
      {
        // Instantiate the DataSet to null
        DataSet ds = null;
    
        // Make an unhandled NullReferenceException
        ds.CaseSensitive = true;
      }

     

    The buttons click event handler uses the ThreadPool to execute the MakeIisCrash() method. This method instantiates a DataSet as null, and the sets a property. Since the DataSet is null, this throws a NullReferenceException which is not handled, as you can see.

    Click the button, and see how IIS will crash.

    You can sense that your computer is working harder - that is because IIS terminates the application pool. If you go and check the Windows Application log, you can see that is has added an error:

    image

    Now this doesn't tell you much. Imagine if you had hundreds of thousands line of code - how would you find the cause of the error?

    Inside Visual Studio, add a new class to the website - call it UnhandledExceptionModule, and apply this code:

    #region Using
    
    using System;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;
    using System.Web;
    
    #endregion
    
    /// <summary>
    /// Handles all unhandled exceptions from in the current AppDomain. 
    /// 
    /// Works great to catch unhandled exceptions thrown by IIS's child threads, 
    /// which will make the application pool terminate unexpectedly

    /// without logging. This makes sure your Exception
    /// is logged to the Application event log. /// </summary> public class UnhandledExceptionModule : IHttpModule { #region Fields private static int _UnhandledExceptionCount = 0; private static string _SourceName = null; private static object _InitLock = new object(); private static bool _Initialized = false; #endregion #region IHttpModule members public void Init(HttpApplication app) { // Do this one time for each AppDomain. if (!_Initialized) { lock (_InitLock) { if (!_Initialized) { string webenginePath = Path.Combine(RuntimeEnvironment.GetRuntimeDirectory(), "webengine.dll"); if (!File.Exists(webenginePath)) { throw new Exception(String.Format(CultureInfo.InvariantCulture,
    "Failed to locate webengine.dll at '{0}'. This module requires .NET Framework 2.0.", webenginePath)); } FileVersionInfo ver = FileVersionInfo.GetVersionInfo(webenginePath); _SourceName = string.Format(CultureInfo.InvariantCulture, "ASP.NET {0}.{1}.{2}.0", ver.FileMajorPart,
    ver.FileMinorPart, ver.FileBuildPart); if (!EventLog.SourceExists(_SourceName)) { throw new Exception(String.Format(CultureInfo.InvariantCulture,
    "There is no EventLog source named '{0}'. This module requires .NET Framework 2.0.", _SourceName)); } AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(OnUnhandledException); _Initialized = true; } } } } public void Dispose() { } #endregion #region UnhandledException event handler public void OnUnhandledException(object o, UnhandledExceptionEventArgs e) { // Let this occur one time for each AppDomain. if (Interlocked.Exchange(ref _UnhandledExceptionCount, 1) != 0) return; StringBuilder message = new StringBuilder("\r\n\r\nUnhandledException logged by UnhandledExceptionModule:\r\n\r\nappId="); string appId = (string)AppDomain.CurrentDomain.GetData(".appId"); if (appId != null) { message.Append(appId); } Exception currentException = null; for (currentException = (Exception)e.ExceptionObject; currentException != null; currentException = currentException.InnerException) { message.AppendFormat("\r\n\r\ntype={0}\r\n\r\nmessage={1}\r\n\r\nstack=\r\n{2}\r\n\r\n", currentException.GetType().FullName, currentException.Message, currentException.StackTrace); } EventLog Log = new EventLog(); Log.Source = _SourceName; Log.WriteEntry(message.ToString(), EventLogEntryType.Error); } #endregion }

     

    Modify the httpModules section inside web.config to look lige this:

            <httpModules>
    <add type="UnhandledExceptionModule" name="UnhandledExceptionModule"/>
    </httpModules>

     

    This is your new friend. It is a must for any ASP.NET 2.0 application running in production environment. This will catch your exception, and write the message and the stack trace to the Windows Application Event log, and now you can see what caused the crash:

    image

    So after we applied this HttpModule to our production environment, we get a nice entry in our Application event log from ASP.NET. It includes a stack trace, which makes us able to find the problem, and fix it!

    Further reading regarding ASP.NET production environment issues:

    Hope this will help someone.

     

    Technorati Tags: , , ,

     

    kick it on DotNetKicks.com

    Currently rated 5.0 by 3 people

    • Currently 5/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    Add to: Facebook Add to: Digg Add to: Del.icio.us Add to: Reddit Add to: Furl Add to: Yahoo Add to: Spurl Add to: Google Add to: Technorati
    Tags: , , ,
    Categories: ASP.NET | IIS7 | .NET
    Actions: E-mail | Permalink | Comments (3) | Comment RSSRSS comment feed

    Web services and Silverlight 1.1 C# gotchas

    September 4, 2007 18:51 by MartinHN

    As anyone must know by now, Silverlight is Microsoft's cross-browser, cross-platform RIA (Rich Internet Application) technology - like Adobe's Flash. With Silverlight, they say the sky is the limit, and it's only up to yourself what to invent. Silverlight offers you a big chunck of the .NET CLR in the browser, when using Silverlight 1.1 Alpha (Refresh). As always, there are do's and don'ts when you work with new technology and in this not-known-yet-part series, I'm going to recap my experience using Silverlight 1.1 Alpha and later Silverlight 1.1 Alpha Refresh to develop some sophisticated charting components.

    Before you begin - general info

    For the current release of Silverlight (Silverlight 1.1 Alpha Refresh) you don't have the System.Data namespace (that means no DataSets nor DataTables). Also the System.Xml namespace is very small, you don't get the XmlDocument which would have been useful. I haven't heard anything reliable about whether or not those namespaces and classes will make it into the final release of Silverlight, but it doesn't seem like it.

    Maybe 3rd party components will come to help here, but that's a drawback because then the users have to install something new on their machines to be able to use your app.

    Mark your webservice as a ScriptService

    If you're going to use any kind of data in your Silverlight apps, and you probably are, then you have to use a webservice. Calling a webservice from Silverlight is a bit different from calling a webservice from another ASP.NET page.

    First of all, you have to mark your webservice as Scriptable. The Scriptable attribute excists in the System.Web.Script.Services namespace, and is part of the ASP.NET AJAX framework (also included in the .NET Framework 3.5). If you are developing on ASP.NET 2.0, you have to make sure you have ASP.NET AJAX installed on the server, and reference the correct assemblies in your ASP.NET 2.0 application.

    This is how your class definition will look like:

    [WebService(Namespace = http://tempuri.org/)]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.Web.Script.Services.ScriptService]
    public class SilverchartDataService : System.Web.Services.WebService{
    
    } 
    


    Now your webservice can be called from Silverlight - and also JavaScript / AJAX.

    Don't call a webservice on another domain

    The security model of Silverlight, and also other client-side technologies, deny calling a webservice on another domain. That is also called cross-domain webservice calls, and if you do, you will get this exception when #debugging your Silverlight app using Visual Studio 2008:

    image

    I've seen ways to get around this problem, but it is beyond the purpose of this blog post. If you need info on this topic, try this: Using a proxy to access remote APIs (The article is for AJAX - should work for Silverlight)

    JSON Serialization compatibillity with .NET

    Whenever you use a webservice, all the objects transfered gets serialized. (Remember to mark your own classes as Serializable if you want to use them in your webservice.) And Silverlight uses the JSON Serialization 'engine'. This can result in some nasty errors, yet difficult to debug. I've found out, that some .NET classes cannot be used - these include:

    • decimal
    • enum (So don't use enum's with Silverlight - at least not until it is supported)

    And there are probably more than those two...

    Technorati Tags: , , ,

    Currently rated 5.0 by 1 people

    • Currently 5/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    Add to: Facebook Add to: Digg Add to: Del.icio.us Add to: Reddit Add to: Furl Add to: Yahoo Add to: Spurl Add to: Google Add to: Technorati

    Links: ASP.NET, ASP.NET AJAX, IIS7, Visual Studio, Silverlight, .NET

    August 30, 2007 19:40 by MartinHN

    Scott Guthrie, has posted some new and great links for some of his technologies. Scott always give a good introduction to new technology as well. He's doing some series on LINQ, and you can find a lot of great tips and tricks, in his ASP.NET 2.0 Tips, Tricks, Recipes and Gotchas series - don't hesitate to leave a comment - he works really hard to answer most of them. Great!


    Be the first to rate this post

    • Currently 0/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5