Contact
Send mail to the author(s) Email Me

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Sign In
Navigation

Tag Cloud
.NET Framework (31) AJAX (9) ASP.NET (16) ASP.NET MVC (3) C# (32) Cloud (2) Database (6) Dev Community (2) Dev Tools (5) Enterprise Library (1) Futures (2) General (6) IIS (1) Javascript (7) LINQ (2) Mobile (1) MSDTC (5) Quotes (3) SQL (3) Transactions (4) Visual Studio (3) WAS (2) WCF (20) WIF (1)

Archive
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

Categories

Blogroll
Home Feed your aggregator (RSS 2.0)
# Sunday, January 31, 2010

I’m not sure if what I’m doing is actually the right way to create a “user control” in ASP.NET MVC, but it’s worth sharing this tidbit either way. Instead of using a MVC View User Control to create a hidden field, a text box, two anchors, and three JavaScript functions, I chose to put it all in a HtmlHelper in which I write out the HTML and JavaScript myself. Everything worked fine except the almost magical auto-repopulating of the hidden and text fields after a post that didn’t work as expected as in a typical MVC View Page.

The situation: I have a page that needs to be called as a popup from many pages in my MVC application. The page allows single or multiple selection of “items” driven by an XML file. In the event that one day, almost always immediately, I have two or more of these “controls” on one view page, I need the two fields and the three JavaScript functions to have unique names so they don’t cross paths and cause unexpected behavior. I had an ASP.NET User Control to do this in plain old ASP.NET (POAN) since v1.1, and I can’t live without it.

The confusion: If I were to place the hidden, textbox, anchors, and JavaScript functions directly in the calling page, something magical happens after a post. If the controls had values before the post, they appear to magically retain there values after the post. It wasn’t until a colleague of mine, Sat, and I dug into Reflector for a while did we realize what was happening. Html.TextBox, Html.Hidden, and others all do something similar to auto-magically re-populate their values after the post. Since I’m writing out my fields as <input type=”hidden”/> and <input type=”text”/>, the magic doesn’t happen.

      NOTE: The magic will also not happen if you just write <input type=”text”/> on the page. It only happens if you use Html.TextBox.

The solution: I am still new to MVC and still trying to wrap my head around the “right way” to do things. Reflector showed that the HtmlHelpers all looked at the ModelState in the ViewData before rendering their HTML. They looked for their value by key (key being the control/tag name), and, if present, used that as the control/tag’s value. Bing! Maybe I should do the same thing. So just before I go to town with TagBuilder to assemble my controls/tags, I look in the ViewData’s ModelState for my value. If it is there, it must have been posted there by me (my control).

   48         UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext);

   49         string textValue = null;

   50         ModelState state;

   51 

   52         if (helper.ViewData.ModelState.TryGetValue(textFieldName, out state))

   53         {

   54             textValue = state.Value.AttemptedValue;

   55         }


Works like a charm! Now my hidden, textbox, two anchors, and three JavaScript functions are bundled nicely inside of an HtmlHelper class that looks and feels like I’m using a built-in ASP.NET MVC HtmlHelper class. Most importantly, I have the pleasure of typing only this on all my consuming pages.

   40     <%= Html.MySelector("selectedIDs", "selectedNames", "State")%>

Sunday, January 31, 2010 9:50:19 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]   ASP.NET | ASP.NET MVC | C# | Javascript  | 
# Thursday, November 26, 2009

I’ve been talking about Geneva for a long time. I got the basics down earlier in the year. I tried to come up with my own set of sample apps, but failed to get anywhere. With the official release, and renaming to Windows Identity Foundation (WIF), I have renewed inspiration.

I read Michele Leroux Bustamante’s MSDN magazine article, Claim-Based Authorization with WIF, last night. After reading the article, I was confident that I could get a claims-aware WCF service stood up with a custom STS in a matter of hours. Today I downloaded and installed WIF. I also installed the WIF SDK and all of the prerequisite hotfixes. I perused the readme files and looked through some of the samples code. Everything is layed out sensibly, the samples are commented sufficiently, and the samples include setup and cleanup batch scripts when necessary.

The samples include:

Quick Start

  1. Simple Claims Aware Web Application
  2. Simple Claims Aware Web Service
  3. Simple Web Application With Information Card SignIn
  4. Simple Web Application With Managed STS
  5. Claims Aware Web Application in a Web Farm
  6. Using Claims In IsInRole

End-to-end Scenario

  1. Authentication Assurance
  2. Federation For Web Services
  3. Federation For Web Applications
  4. Identity Delegation
  5. Web Application With Multiple SignIn Methods
  6. Federation Metadata

Extensibility

  1. Claims Aware AJAX Application
  2. Convert Claims To NT Token
  3. Customizing Request Security Token
  4. Customizing Token
  5. WSTrustChannel
  6. Claims-based Authorization

All of the samples I’ve run through so far are great. The only thing that I’m not in love with is all the XML required to wire this stuff up. Maybe some Juval-style extensions would make it less painful.

One more thing… it looks like all of the XP users will finally have to upgrade. WIF only works with Vista, Win7, and Win2008. I heard that Win2003 compatibility will arrive in December.

Download Windows Identity Foundation

Download Windows Identity Foundation SDK

Thursday, November 26, 2009 11:44:24 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]   .NET Framework | AJAX | ASP.NET | C# | WCF | WIF  | 
# Sunday, September 21, 2008

WCF never ceases to amaze me. Around every corner is another fascinating use for WCF, and much forethought on Microsoft's part to make it look and behave great. I wanted to expose my services to my AJAX functions on my web site. I did not want to change my class library because it is used by other clients. I could just add the service classes to this web site, but why re-do when you can re-use.

If you have an existing WCF Service Library, you will need to expose it with the AspNetCompatibilityRequirementsMode.Allowed attribute on the service class to make it visible to ASP.NET clients. To avoid changing your service library in any way, the easiest thing to do is to add a new class to your web site that inherits from your service class. In this example, my existing service library uses the JeepServices namespace. Notice there is no implementation in this class. It is simply a placeholder for the real service implementation with the compatibility attribute attached.

    1 using System.ServiceModel;

    2 using System.ServiceModel.Activation;

    3 

    4 [ServiceBehavior]

    5 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]

    6 public class WebHttpService : JeepServices.Service

    7 {

    8 }

Now that I have a ASP.NET compatible service, I need to expose it to the web site clients. Create a service file (.svc), and change the Service and CodeBehind attributes to point to the .svc file. The last thing you need is the Factory attribute. This notifies WCF of this service, eliminating the need for a configuration file entry for the service endpoint. In fact, you don't even need the <system.servicemodel> in your configuration file at all. This is because it is only hosted as a web script, and cannot be called outside of the web site.

    1 <%@ ServiceHost Language="C#" Debug="true" Service="WebHttpService" CodeBehind="~/App_Code/WebHttpService.cs"

    2     Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory" %>

 

In your web page you will need a few things. First your will need a ScriptManager with a ServiceReference to the .svc file. You will then need the Javascript functions to make the call (DoJeepWork), handle the success message (OnJeepWorkSucceeded), and handle the failure message (OnJeepWorkFailed). Notice in DoJeepWork that you don't call the service by it's service name WebHttpService, you call it by the ServiceContract namespace and name. For this example, my interface has ServiceContract attributes Namespace = "JeepServices", and Name = "JeepServiceContract". Now you just wire up a ASP.NET control's OnClientClick or an input or anchor tag's onclick to DoJeepWork() and you are good to go.

    1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

    2 

    3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

    4 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    5 <html xmlns="http://www.w3.org/1999/xhtml">

    6 <head runat="server">

    7     <title>Test page</title>

    8 

    9     <script type="text/javascript">

   10         function DoJeepWork() {

   11             JeepServices.JeepServiceContract.DoWork(OnJeepWorkSuccedeed, OnJeepWorkFailed);

   12         }

   13         function OnJeepWorkSuccedeed(res) {

   14             document.getElementById("<%= this.lblMessage.ClientID %>").innerText = res;

   15         }

   16         function OnJeepWorkFailed(error) {

   17             // Alert user to the error.   

   18             alert(error.get_message());

   19         }

   20     </script>

   21 

   22 </head>

   23 <body>

   24     <form id="form1" runat="server">

   25     <div>

   26         <asp:ScriptManager runat="server">

   27             <Services>

   28                 <asp:ServiceReference Path="~/Services/WebHttpService.svc" InlineScript="false" />

   29             </Services>

   30         </asp:ScriptManager>

   31         <asp:Label ID="lblMessage" runat="server" Text="No work has been done" />

   32         <a href="javascript:void(0); DoJeepWork()">Do Work</a>

   33     </div>

   34     </form>

   35 </body>

   36 </html>

 

Mission accomplished! Here you've seen how to expose an existing WCF service library without changing any code in the library itself. Adding two files allowed the service to be exposed to your AJAX clients. Best of all, there is no configuration file changes to make.

Useful Links:

Sunday, September 21, 2008 11:21:24 AM (Eastern Standard Time, UTC-05:00)  #    Comments [9]   .NET Framework | AJAX | ASP.NET | C# | Javascript | WCF  | 
# Sunday, January 20, 2008

In a previous post about the AJAX Extensions, I detailed the copy commands to retrieve the DLLs from the GAC. Same thing, this time for the ASP.NET 3.5 Extensions. If you are demoing CTP material in a hosted environment, you will likely need these in your app's bin to avoid the inevitable configuration error.

copy "C:\WINDOWS\assembly\GAC_MSIL\System.Web.Extensions\3.6.0.0__31bf3856ad364e35" C:\dev\MMVCApp\bin
copy "C:\WINDOWS\assembly\GAC_MSIL\System.Web.Extensions.Design\3.6.0.0__31bf3856ad364e35" C:\dev\MMVCApp\bin

Sunday, January 20, 2008 10:25:40 PM (Eastern Standard Time, UTC-05:00)  #    Comments [6]   .NET Framework | ASP.NET | ASP.NET MVC | C#  | 
# Tuesday, December 18, 2007

A great series of blog posts by Scott Guthrie about the ASP.NET MVC Framework coming soon as part of the ASP.NET 3.5 Extensions release.

Upon hearing the news, a few friends started questioning its intent, usefulness, and longevity. Many of us have been using or contemplating conversion to the MVP pattern, most recently using WCSF. The recent split of the MVP pattern by Fowler has caused many believers to question their faith. While many are still "proving" MVP, MVC has been around for nearly 30 years. Some believe that MVP and MVC can co-exist. Here is a comparison of MVP and MVC that concludes by painting an optimistic picture of MVP and MVC contributing to each other.

ASP.NET MVC appears to be the answer to my unit testing, REST, and code separation prayers. Thank you ScottGu and team!

Check it out!

Tuesday, December 18, 2007 9:06:20 PM (Eastern Standard Time, UTC-05:00)  #    Comments [3]   .NET Framework | AJAX | ASP.NET | ASP.NET MVC | C# | Javascript  | 
# Wednesday, November 21, 2007
Wednesday, November 21, 2007 10:08:56 PM (Eastern Standard Time, UTC-05:00)  #    Comments [8]   .NET Framework | ASP.NET | C#  | 
# Thursday, August 16, 2007

It's only a week away, and there are still spaces left.

Information   Register    Sessions

Thursday, August 16, 2007 10:42:12 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]   .NET Framework | AJAX | ASP.NET | C# | Database | General | Javascript  | 
# Saturday, February 10, 2007

Many hosting companies, like mine, won't have the AJAX Extensions installed in the GAC for quite a while, if ever.   No worries, you can just put the DLLs in your Bin folder.   Since MS hasn't graced us with the DLLs, so you'll have to get them out of your GAC.  I haven't found a way to copy DLLs using Windows Explorer, but command-line never fails.

copy "C:\WINDOWS\assembly\GAC_MSIL\System.Web.Extensions\1.0.61025.0__31bf3856ad364e35" C:\dev\MyApp\Bin\
copy "C:\WINDOWS\assembly\GAC_MSIL\System.Web.Extensions.Design\1.0.61025.0__31bf3856ad364e35" C:\dev\MyApp\Bin\

Saturday, February 10, 2007 2:50:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments [4]   .NET Framework | AJAX | ASP.NET  | 

I frequently place an UpdatePanel around a paged GridView with inline editing.   During OnRowUpdating, the object is saved.   If the save was not successful, I like to show an alert box with the error message.  

I recently migrated from the Atlas May CTP to ASP.NET 2.0 AJAX.   The following code worked with the May CTP, but, from my research, has not worked since July CTP:

Page.ClientScript.RegisterStartupScript(typeof(string), "alertScript", "alert('Error Message');", true);

However, our pals at Microsoft have given us something just as good.   I found it by mistake while trying to put in a hack involving checking the value of ScriptManager.GetCurrent(Page).IsInAsyncPostBack.  Here is the AJAX-friendly equivalent:

ScriptManager.RegisterStartupScript(this.updatePanel, typeof(string), "alertScript", "alert('Error Message');", true);

Hope this helps someone.  There are many blog posts, with many more comments, with people compaining about this.

Saturday, February 10, 2007 8:21:42 AM (Eastern Standard Time, UTC-05:00)  #    Comments [30]   AJAX | ASP.NET  | 
# Wednesday, February 07, 2007

I just migrated from the Atlas July CTP to ASP.NET 2.0 AJAX Extensions 1.0.  After following all of the instructions on the AJAX site, my web site still showed tons of errors.  I'm using a Web Site, not Web Application, with a ScriptManager in a WebForm that uses a MasterPage.   Every page shows errors on AJAX tags. 

Yes, I removed the Atlas DLL.  No, my web.config is not messed up.  Something else is wrong here.   I found a "fix".   The sequence of steps seems a little odd to me, but I did't care, it worked.  However, the problem resurfaced when I closed my MasterPage.

More searching led me to a great alternative to a true solution.   An ASP.NET Forums post had some back-and-forth on the topic.  Ultimately, the best solution at this point is to change the tagprefix to "ajax".   This works great, and, in fact, I like it better because it separates the ajax controls from the standard asp controls.

<add tagPrefix="ajax" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

Wednesday, February 07, 2007 9:34:09 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]   AJAX | ASP.NET  | 
# Monday, November 06, 2006

I frequently store documents in the database for my ASP.NET apps, eliminating web farm complications with shared drives, permissions, etc.  When uploading a file, my Document class reads the uploaded file, zips the file with SharpZipLib, and inserts/updates in the database.   When opening a file, I have always used an ASPX page that uses the Document class to unzip the file, and then changes the Content-Disposition and ContentType headers, and then does a BinaryWrite to the Response object to display the file.

I have been using Handlers a lot lately, and figured that it was time to make this process a little more elegant.  If you've never written a handler, it's quite simple.  You need to make a web.config change, and add a new class that implementts IHttpHandler.  All of the work is done in ProcessRequest.  Using the default .ashx extension for the handler eliminates the need to make any changes in IIS.  I thought about changing the handler to accept all requests with known file extensions with the document ID as the filename, like 3383.pdf.  I just figured that using the default extnesion would be easier.   Laziness or efficiency, you decide.  Check out the code.

In <system.web> in web.config:


<httpHandlers>
   
<add verb="*" path="DocumentHandler.ashx" type="TestingWebApp.DocumentHandler, TestingWebApp" />
</httpHandlers>

DocumentHandler.cs:


using System;
using System.Web;

namespace TestingWebApp
{
    public class DocumentHandler : IHttpHandler
    {
        private int DocumentId
        {
            get
            {
                if(System.Web.HttpContext.Current.Request.QueryString["DocumentId"] != null && System.Web.HttpContext.Current.Request.QueryString["DocumentId"].ToString().Length > 0)
                    return Convert.ToInt32(System.Web.HttpContext.Current.Request.QueryString["DocumentId"]);
                else
                    throw new ApplicationException("Document Handler requires a DocumentId");
            }
        }

        #region IHttpHandler Members

        public void ProcessRequest(System.Web.HttpContext context)
        {
            context.Response.Cache.SetCacheability(HttpCacheability.Public);
            context.Response.BufferOutput = false;
            
            Document document = Document.GetDocumentByDocumentId(this.DocumentId);

            byte[] buffer = document.UnzippedBinary;
            context.Response.ContentType = document.ContentType;
            context.Response.OutputStream.Write(buffer, 0, buffer.Length);
        }

        public bool IsReusable
        {
            get { return true; }
        }

        #endregion
    }
}
Monday, November 06, 2006 11:31:15 PM (Eastern Standard Time, UTC-05:00)  #    Comments [5]   .NET Framework | ASP.NET | C# | Database  | 
# Sunday, November 05, 2006

The starter kit already allowed individual file upload, and batch upload from a directory which requires files to be moved to Upload directory by FTP.  The starter kit also stores the images in the database. While I prefer this method for most files, I don't prefer it for images. I changed a few methods to store the images in an images folder, and modified the image serving handler accordingly.  The album page load time is a fraction of what it was with images in the database.

I also created an XP Publishing Wizard that allows any user with credentials to create/choose an album, and upload images from Windows XP. The beauty of the XPPW is that it can resize the images before uploading. That way all of us with 10 megapixel cameras no longer have to spend any extra time resizing to prevent reaching a web host storage quota.

A few articles helped me figure this stuff out:

Creating the wizard was easy enough.  You first need to create a registry entry in the following format:

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\PublishingWizard\PublishingWizard\Providers\Your Photo Gallery]
"displayname"="Your Photo Gallery"
"description"="Online Photo Albums"
"href"="http://www.yoursite.net/XPPublish.aspx"
"icon"="http://www.yoursite.net/favicon.ico"

Next is a single aspx page that accepts the files.  The page handles user login, album creation/selection, and accepts multiple files in a single form post.  All the hard work is done by some javascript methods that handle the XML sent from Windows XP.  The javascript looks like this:

        <script language='javascript'>
            function startUpload()
            {
                var xml = window.external.Property("TransferManifest");
                var files = xml.selectNodes("transfermanifest/filelist/file");
                var albumId = document.getElementById("Album").value;

                for (i = 0; i < files.length; i++)
                {
                    var postTag = xml.createNode(1, "post", "");
                    postTag.setAttribute("href", "http://yoursite.net/XPPublish.aspx");

                    postTag.setAttribute("name", "userpicture");

                    var dataTag = xml.createNode(1, "formdata", "");
                    dataTag.setAttribute("name", "MAX_FILE_SIZE");
                    dataTag.text = "10000000";                    
                    postTag.appendChild(dataTag);
                    
                    var dataTag1 = xml.createNode(1, "formdata", "");
                    dataTag1.setAttribute("name", "btnUpload");
                    dataTag1.text = "Save";
                    postTag.appendChild(dataTag1);
                    
                    var dataTag2 = xml.createNode(1, "formdata", "");
                    dataTag2.setAttribute("name", "hidAlbumId");
                    dataTag2.text = albumId;
                    postTag.appendChild(dataTag2);

                    files.item(i).appendChild(postTag);
                }
                
                var uploadTag = xml.createNode(1, "uploadinfo", "");
                uploadTag.setAttribute("friendlyname", "Family Photo Gallery");
                var htmluiTag = xml.createNode(1, "htmlui", "");
                htmluiTag.text = "http://yoursite.net/Personal/Albums/Photos.aspx?AlbumID=" + albumId;
                uploadTag.appendChild(htmluiTag);

                xml.documentElement.appendChild(uploadTag);

                window.external.Property("TransferManifest") = xml;
                window.external.SetWizardButtons(true,true,true);
                document.getElementById("divContent").innerHtml = xml;
                window.external.FinalNext();
            }

            function OnBack()
            {
                window.external.FinalBack();
                window.external.SetWizardButtons(false,true,false);
            }

            function OnNext()
            {
                if (document.getElementById("divLogin"))
                {
                    document.getElementById("LoginArea_Login1_LoginButton").click();
                }
                else
                {
                    startUpload();
                }
            }

            function OnCancel()
            {
            }

            function window.onload()
            {
                window.external.SetHeaderText('Photo Gallery','Your Photos');
                window.external.SetWizardButtons(true,true,false);
            }
        </script>

In case you haven't seen the XP Publishing Wizard in action, check out these screenshots:

 

 

 

 

 

 

 

 

 

Sunday, November 05, 2006 9:35:38 PM (Eastern Standard Time, UTC-05:00)  #    Comments [6]   ASP.NET | Javascript  | 
# Tuesday, August 30, 2005

Rick Strahl delivered another excellent white paper. In addition to his white papers, he has one of the most readable and intelligent blogs on the web.

White paper: Past the AJAX Hype - some things to think about

Tuesday, August 30, 2005 8:57:57 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]   AJAX | ASP.NET | Javascript  | 
# Saturday, July 23, 2005

Dmitri Khanine and Phil Carrillo author this fine article on Javascript RPC. Finally, an article that mentions separation of business and presentation logic, and implementing MVC in ASP.NET. We need more patterns and practices discussions, and a lot less "look what I can do" articles.

MSDN Article: Life without Refresh

Saturday, July 23, 2005 9:01:30 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]   AJAX | ASP.NET | Javascript  | 
# Saturday, June 04, 2005

Devloping an application using the System.Web.Mail.SmtpMail class to send email should not be as difficult as it always is. http://www.systemwebmail.com has a detailed and helpful collection of possible fixes for the dreaded "Could not access 'CDO.Message' Object" Exception. The one I most recently experienced was not listed. We thought it could be a relaying perrmission or something related to setting the SmtpServer name. It turned out to be a Windows 2003-specific problem related to Fixed Identity Impersonation for high security (isolated) applications using a low-privilege user account specific to the application.

The exception you see, almost always the useless excpetion, "Could not access 'CDO.Message' Object", does not help you to troubleshoot. As you can see in the code below, generated using Lutz Roeder's .NET Reflector, called by SmtpMail.Send(), the real exception is never thrown. It will throw the "Could not access 'CDO.Message' Object" exception no matter what exception was caught.

internal object CallMethod(object obj, string methodName, object[] args)
{
   object obj1;
   try
   {
      obj1 = SmtpMail.LateBoundAccessHelper.CallMethod(
         this.LateBoundType, obj, methodName, args);
   }
   catch (Exception exception1)
   {
      throw new HttpException(HttpRuntime.FormatResourceString(
         "Could_not_access_object", this._progId), exception1);
   }
   return obj1;
}

The best advice given by http://www.systemwebmail.com is to loop through all of the InnerExceptions thrown when the useless exception is thrown. This will allow you to see the true exception and determine how to fix the problem.

In Windows 2003, you can have each application run in its own application pool using an application-specific user account. Depending on the privileges and group memberships of this user account, it may or may not have the correct permissions to be able to send mail using the machine's SMTP server. To send mail, the user account needs to have write permissions on the directory named C:\inetpub\mailroot\Pickup. With those permissions, System.Web.Mail (.NET wrapper around CDOSys.dll) will create a .eml file in that directory. The mail gets sent when the SMTP service, with SYSTEM privileges, sees this file and sends the email.

If granting the necessary permissions is not possible for your application's user account, you can bypass System.Web.Mail's default CDO send method, using the Pickup directory, altogether. You can modify the mail message's configuration fields to set the values used by CDO, regardless of the values set by System.Web.Mail.

You can send the mail message by going through the smtp port instead of the pickup directory (default). Change the sendusing configuration field from 0 (default - pickup directory) to 1 (port).

mailMsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusing", 1);

If you still cannot send email, try using other CDO configuration fields to bypass the System.Web.Mail settings. Here are some other configuration fields. I would try them in this order:

// smtpauthenticate values (2=NTLM, 1=Basic, 0=None)
mailMsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", 1);
mailMsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserverport", 25);
mailMsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserver", mailServer);
mailMsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", username);
mailMsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", pw);
mailMsg.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout", 10);


Of course, all of this is only possible if you are using .NET Framework 1.1. The Fields property of the MailMessage class was not exposed in version 1.0 of the framework.

Saturday, June 04, 2005 9:02:18 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]   ASP.NET | C#  | 
# Saturday, October 16, 2004

DropDownLists within a Repeater appear to lose or forget which item is selected before the page loads. This is not the case. Dynamically created DropDownLists inside of a Repeater create a rare obstacle. The SelectedItem is not being lost or forgotten. It only appears that way because the OnDataBinding event for the DropDownList is being called twice. Only when the RepeaterItem containing the DropDownList calls its own DataBind method is the data actually bound to the DropDownList. Consider the following code:

// UsingDropDownLists.aspx
115 <asp:Repeater id="rptOne" runat="server" OnItemCreated="rptOne_ItemCreated"/>
116  <ItemTemplate>
117    <asp:Literal id="litQuestion" runat="server"/>
118    <asp:DropDownList id="ddlResponse" runat="server"/>
119    <br/>
120  </ItemTemplate>
121 </asp:Repeater>

// UsingDropDownLists.aspx.cs
211 protected void rptOne_ItemCreated(object sender, RepeaterItemEventArgs e)
212 {
213   if(e.Item.DataItem != null)
214   {
215     MyClass myClass = sender as MyClass;
216     (e.Item.FindControl("litQuestion") as Literal).Text = myClass.Question;
217     DropDownList ddl = e.Item.FindControl("ddlResponse") as DropDownList;
218     ddl.DataSource = GetResponseList(myClass.AvailableResponses);
219     ddl.Items.FindByValue(myClass.Response).Selected = true;
220     ddl.DataBind();
221     ddl.SelectedIndex = e.Item.ItemIndex%(ddl.Items.Count-1); //Random
222   }
223 }

Here is the sequence of events:
  1. Page_Load
  2. Data Retrieval/Bind Data to Repeater
  3. Repeater's ItemCreated event fires for each RepeaterItem
  4. Data Retrieval/Bind Data to DropDownList
  5. OnDataBinding is fired from the DropDownList's DataBind() (line 220). However, if you watch in debug mode, you will see that the DropDownList has no ListItems yet.
  6. DropDownList's SelectedIndex is chosen (line 221). Although, at this point, the DropDownList still has no ListItems. The SelectedIndex call falls on deaf ears.
  7. RepeaterItem's DataBind method performs an actual DataBind on the DropDownList. There are no selected items at this point.

RepeaterItem inherits from Control. If you look at Control's DataBind() method in Lutz Roeder's .NET Reflector, you will see that it performs a DataBind on each of its child controls. 

public virtual void DataBind()
{
   this.OnDataBinding(EventArgs.Empty);
   if (this._controls != null)
   {
      string text1 = this._controls.SetCollectionReadOnly("Parent_collections_readonly");
      int num1 = this._controls.Count;
      for (int num2 = 0; num2 < num1; num2++)
      {
         this._controls[num2].DataBind();
      }

      this._controls.SetCollectionReadOnly(text1);
   }
}

From this, we can see three things.

  1. The only safe time to choose the SelectedItem is after the binding of all objects within the Repeater. A perfect place to do this is in the RepeaterItem's PreRender or in the Repeater's PreRender. You have access to the same bound object from RepeaterItem.DataItem, and can find the DropDownList and choose the SelectedIndex, SelectedValue, or ddl.Items.FindByValue(response).Selected = true;
  2. The DataBind() call (line 220) is completely unnecessary and leads the programmer to believe that it has actually bound the data. This is untrue. Again, in debug mode, you will see that by line 221, there are still zero ListItems in ddl.Items.
  3. The same obstacle will arise for all Controls derived from ListControl. This includes CheckBoxList, DropDownList, ListBox, and RadioButtonList. The same solution will apply to these controls within a Repeater.

Saturday, October 16, 2004 9:03:32 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]   ASP.NET | C#  | 
Copyright © 2010 Scott Klueppel. All rights reserved.