<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>ASP.NET</title>
        <link>http://www.alexkuo.info/category/3.aspx</link>
        <description>Blurbs about ASP.NET development and the Microsoft platform.</description>
        <language>en-US</language>
        <copyright>Alex Kuo</copyright>
        <generator>Subtext Version 1.9.4.0</generator>
        <item>
            <title>ASP.NET: Modifying DetailsView Select and Updating Events </title>
            <link>http://alexkuo.info/archive/2009/08/09/ASPNET_DetailsView_Modify_Updating_Event.aspx</link>
            <description>Recently I was tasked with encrypting/decrypting some data that could be edited using ASP.NET's DetailsView control.  Along with the details view control, the legacy code used a SQL Data Source to select and update everything. This means the data access layer was bypassed completely, so any business logic that dealt with encryption on this page had to use a different execution path. So, how would you encrypt and decrypt data?&lt;br /&gt;
&lt;br /&gt;
The problem could be divided into two tasks:&lt;br /&gt;
&lt;ol&gt;
    &lt;li&gt;Create a filter to decrypt data in any bound columns.&lt;/li&gt;
    &lt;li&gt;Edit the DetailsView event, ItemUpdating and figure out which columns needed to be updated during the event.&lt;/li&gt;
&lt;/ol&gt;
The first task was the easier of the two, as it just involved referencing the encryption library from the code behind page and calling the function inline in the aspx page. So, the method in the code behind page would look like something like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: 640px; height: 80px; text-align: left;" dir="ltr" class="alt2"&gt;protected string Decrypt(object input)&lt;br /&gt;{&lt;br /&gt;     return EncryptionHelper.Decrypt(input.ToString());&lt;br /&gt;}&lt;/pre&gt;
&lt;br /&gt;
While calling the decrypt function in the DetailsView child  Fields tags on the aspx page:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="alt2" dir="ltr" style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: 800px; height: 175px; text-align: left;"&gt;&amp;lt;asp:templatefield headertext="Decrypted Data" sortexpression="EncryptedData&amp;gt;&lt;br /&gt;    &amp;lt;edititemtemplate&amp;gt;     &lt;br /&gt;     &amp;lt;asp:TextBox ID="TextBox1" runat="Server" Text='&amp;lt;%#Decrypt(Eval("EncryptedData"))%&amp;gt;' /&amp;gt;&lt;br /&gt;    &amp;lt;/edititemtemplate&amp;gt;&lt;br /&gt;    &amp;lt;itemtemplate&amp;gt;&lt;br /&gt;      &amp;lt;asp:label runat="server" text='&amp;lt;%# Decrypt(Eval("EncryptedData")) %&amp;gt;' id="Label1"&amp;gt;&amp;lt;/asp:label&amp;gt;&lt;br /&gt; &amp;lt;/itemtemplate&amp;gt;&lt;br /&gt;&amp;lt;/asp:templatefield&amp;gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;
However, decrypting the data using a templatefield tag posed another problem, extracting new values from the 'TextBox1' control. This will be solved when calling the ItemUpdating event.&lt;br /&gt;
&lt;br /&gt;
After setting the DetailsView's ItemUpdating method, you will need to modify the SQL Data Source's UpdateCommand, UpdateCommandType, and UpdateParameters. The legacy code in the SQL data source used a update statement with parameters. Normally the details view control automatically detects whether to pass a null in the parameter. Instead when  setting the UpdateParameters in the codebehind, the control will update the database with the parameter names entered. For example '@Parameter', will be sent in the update to the record instead of null. To solve this, you would need to automatically detect whether a value is null and then add it to the UpdateParameters list. This was done using the 'IsFieldNull' method [shown below].&lt;br /&gt;
&lt;br /&gt;
Initializing the SQL data source also had another problem - because certain data needed to be re-encrypted before being sent back to the database. You will need to single out any columns that need to be encrypted. On top of that, the table being updated had over 50 columns, so typing in 50+ lines just to initialize the parameters was required, but I decided to do something else instead.&lt;br /&gt;
&lt;br /&gt;
The parameters being sent to the stored procedure were identically named to the column names. Using this protocol, I decided to simply grab all the field names, which were identical to the column names and add the '@' character next during initialization. So, the method to get the column names looked like the following:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="alt2" dir="ltr" style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: 640px; height: 200px; text-align: left;"&gt;private List&amp;lt;string&amp;gt; GetColumnNameList()&lt;br /&gt;{&lt;br /&gt;  List&amp;lt;string&amp;gt; Ret = new List&amp;lt;string&amp;gt;();&lt;br /&gt;&lt;br /&gt;  for (int i = 0; i &amp;lt; DetailsView.Rows.Count; i++)&lt;br /&gt;  {&lt;br /&gt;    if (!String.IsNullOrEmpty(DetailsView.Rows[i].Cells[0].Text))&lt;br /&gt;    {&lt;br /&gt;      Ret.Add(DetailsView.Rows[i].Cells[0].Text);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  return Ret;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;
Initializing the update parameters looked like the following:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="alt2" dir="ltr" style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: 640px; height: 300px; text-align: left;"&gt;private void InitSqlDataSource()&lt;br /&gt;{&lt;br /&gt;   SQLDataSource.UpdateCommand = "Update";&lt;br /&gt;   SQLDataSource.UpdateParameters.Clear();&lt;br /&gt;&lt;br /&gt;   List&amp;lt;string&amp;gt; paramList = GetColumnNameList();&lt;br /&gt;&lt;br /&gt;   foreach (string col in paramList)&lt;br /&gt;   {&lt;br /&gt;      if (!IsFieldNull(col))&lt;br /&gt;      {&lt;br /&gt;         if (col != "EncryptedData")&lt;br /&gt;         {&lt;br /&gt;           SQLDataSource.UpdateParameters.Add(col, "@" + col);&lt;br /&gt;         }&lt;br /&gt;         else&lt;br /&gt;         {&lt;br /&gt;           SQLDataSource.UpdateParameters.Add("EncrptedData", &lt;br /&gt;                 EncryptionHeper.Encrypt(GetDecryptedValue()));&lt;br /&gt;         }&lt;br /&gt;      }&lt;br /&gt;   }  &lt;br /&gt;}&lt;/pre&gt;
&lt;br /&gt;
The method checks to make sure the data being sent isn't blank or null by executing the 'IsFieldNull' method. This method uses the 'ExtractValuesFromCell' method to grab values from the DetailsView control. This method isn't exactly well documented on MSDN, so it's not obvious at first that the passed parameter, IOrderedDictionary dictionary, is being used as a referenced parameter, not as a copy. [another weird quirk about the .NET framework] The method, GetValues, used is identical to what is covered at the article written at &lt;a href="http://weblogs.asp.net/davidfowler/archive/2008/12/12/getting-your-data-out-of-the-data-controls.aspx?CommentPosted=true"&gt;David Fowler's blog&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class="alt2" dir="ltr" style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: 700px; height: 400px; text-align: left;"&gt;private bool IsFieldNull(string fieldName)&lt;br /&gt;{&lt;br /&gt;    OrderedDictionary vals = GetValues(DetailsView) as OrderedDictionary;&lt;br /&gt;&lt;br /&gt;    if (vals[fieldName] == null)&lt;br /&gt;    {&lt;br /&gt;        return true;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return string.IsNullOrEmpty(vals[fieldName].ToString());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public IDictionary GetValues(DetailsView detailsView)&lt;br /&gt;{&lt;br /&gt;    IOrderedDictionary values = new OrderedDictionary();&lt;br /&gt;&lt;br /&gt;    foreach (DetailsViewRow row in detailsView.Rows)&lt;br /&gt;    {&lt;br /&gt;        if (row.RowType != DataControlRowType.DataRow)&lt;br /&gt;        {&lt;br /&gt;            continue;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        DataControlFieldCell dataCell = (DataControlFieldCell)row.Cells[0];&lt;br /&gt; &lt;br /&gt;        if (dataCell.ContainingField.ShowHeader)&lt;br /&gt;        {&lt;br /&gt;            dataCell = (DataControlFieldCell)row.Cells[1];&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        dataCell.ContainingField.ExtractValuesFromCell(values, dataCell, row.RowState, true);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return values;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;img src="http://alexkuo.info/aggbug/53.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Alex Kuo</dc:creator>
            <guid>http://alexkuo.info/archive/2009/08/09/ASPNET_DetailsView_Modify_Updating_Event.aspx</guid>
            <pubDate>Sun, 09 Aug 2009 18:45:49 GMT</pubDate>
            <comments>http://alexkuo.info/archive/2009/08/09/ASPNET_DetailsView_Modify_Updating_Event.aspx#feedback</comments>
            <wfw:commentRss>http://alexkuo.info/comments/commentRss/53.aspx</wfw:commentRss>
            <trackback:ping>http://alexkuo.info/services/trackbacks/53.aspx</trackback:ping>
        </item>
        <item>
            <title>ASP.NET and Retrieving Different Sections of the Current URL using Request.Url</title>
            <link>http://alexkuo.info/archive/2007/09/07/43.aspx</link>
            <description>While working on a project in ASP.NET, I needed a function that would retrieve the domain of the current url, however, I also wanted the function to also retrieve the correct ASP.NET development web server path when developing in Visual Studio. After consulting Google, I ran into &lt;a href="http://west-wind.com/weblog/posts/269.aspx"&gt;this old post&lt;/a&gt; on Rick Strahl's blog about the Request.Url object. &lt;br /&gt;
&lt;br /&gt;
After some experimenting, I created a web page in ASP.NET 2.0 that showed what parts of the URL could be returned using different calls. Consult the following in the page load event.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="alt2" dir="ltr" style="border: 1px inset ; margin: 0px; padding: 6px; overflow: auto; width: 800px; height: 360px; text-align: left;"&gt;    protected void Page_Load(object sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;            Response.Write("Request.Url.AbsolutePath= " + Request.Url.AbsoluteUri);&lt;br /&gt;	    Response.Write("&amp;lt;br&amp;gt;");&lt;br /&gt;            Response.Write("Request.Url.AbsoluteUri= " + Request.Url.AbsoluteUri);&lt;br /&gt;            Response.Write("&amp;lt;br&amp;gt;");&lt;br /&gt;            Response.Write("Request.Url.GetLeftPart(UriPartial.Authority)= " + Request.Url.GetLeftPart(UriPartial.Authority));&lt;br /&gt;            Response.Write("&amp;lt;br&amp;gt;");&lt;br /&gt;            Response.Write("Request.Url.GetLeftPart(UriPartial.Path)= " + Request.Url.GetLeftPart(UriPartial.Path));&lt;br /&gt;            Response.Write("&amp;lt;br&amp;gt;");&lt;br /&gt;            Response.Write("Request.Url.GetLeftPart(UriPartial.Scheme)= " + Request.Url.GetLeftPart(UriPartial.Scheme));&lt;br /&gt;            Response.Write("&amp;lt;br&amp;gt;");	&lt;br /&gt;            Response.Write("Request.RawUrl= " + Request.RawUrl);&lt;br /&gt;            Response.Write("&amp;lt;br&amp;gt;");&lt;br /&gt;            Response.Write("Request.Path= " + Request.Path);&lt;br /&gt;            Response.Write("&amp;lt;br&amp;gt;");&lt;br /&gt;            Response.Write("Request.ApplicationPath= " + Request.ApplicationPath);&lt;br /&gt;            Response.Write("&amp;lt;br&amp;gt;");&lt;br /&gt;            Response.Write("Request.ResolveUrl= " + ResolveUrl("~/dealer/default.aspx"));&lt;br /&gt;            Response.Write("&amp;lt;br&amp;gt;");&lt;br /&gt;            Response.Write("GetAuthorityApplicationPath= " + GetAuthorityApplicationPath());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private String GetAuthorityApplicationPath()&lt;br /&gt;    {&lt;br /&gt;        return String.Concat(Request.Url.GetLeftPart(UriPartial.Authority), Request.ApplicationPath);&lt;br /&gt;    }&lt;/pre&gt;
&lt;br /&gt;
The function GetAuthorityApplicationPath() is what I needed in the end to dynamically retrieve either the domain in a production environment or the development web server url while running Visual Studio (eg. 'http://localhost:1234/WebDirectory')&lt;img src="http://alexkuo.info/aggbug/43.aspx" width="1" height="1" /&gt;</description>
            <guid>http://alexkuo.info/archive/2007/09/07/43.aspx</guid>
            <pubDate>Fri, 07 Sep 2007 10:13:29 GMT</pubDate>
            <comments>http://alexkuo.info/archive/2007/09/07/43.aspx#feedback</comments>
            <wfw:commentRss>http://alexkuo.info/comments/commentRss/43.aspx</wfw:commentRss>
            <trackback:ping>http://alexkuo.info/services/trackbacks/43.aspx</trackback:ping>
        </item>
    </channel>
</rss>
