Blog Archives

Custom DAL Class SQL ORM ASP .NET

(common.DataObject may be of your choosing or may simply replace with dynamic)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Data.SqlClient;

using AIS.Common; //this is a common namespace I use in examples throughout my site
using System.Reflection;
using System.Dynamic;

//TODO: consider returning ienumerable in sp return values for lazy eval vs .tolist immediate eval
namespace AIS.DAL.AppName
{
    public static class StoredProcedures
    {
        public delegate void ErrorHandler(Exception ex);
        /// <summary>
        /// If no custom error handling is bound to this event, exceptions will be thrown back up to the calling function.
        /// If custom handling is bound to this event, ensure it does not perform a redirect or kill the thread unless you intend to abort the procedural
        /// steps following the method/function call which threw the error.
        /// </summary>
        public static event ErrorHandler HandleError;

        #region Unique Procedures
        public static List<Common.DataObject> LoadUserSessions_All(dynamic o)
        {
            return ExecuteRead("an_get_db_fn1", o);
        }

        public static List<Common.DataObject> LoadUserSessionsDetails_LiveStream(dynamic o)
        {
            return ExecuteRead("an_get_db_fn2", o);
        }

        public static List<Common.DataObject> LoadUserSessionsDetails_Live(dynamic o)
        {
            return ExecuteRead("an_get_db_fn3", o);
        }

        public static int LogChat()
        {
            return ExecuteScalar("an_get_db_fn4", null);
        }

        public static int LogError()
        {
            return ExecuteScalar("an_get_db_fn5", null);
        }
        #endregion

        //TODO: consider hiding from external assemblies which would require strong mappings above
        #region Execution Logic
        public static List<Common.DataObject> ExecuteRead(string procedurename, dynamic param)
        {
            try
            {
                SqlDataSource sds = new SqlDataSource();
                sds.ConnectionString = ConfigValues.TrainingPortalConnectionString;
                sds.SelectCommandType = SqlDataSourceCommandType.StoredProcedure;
                sds.SelectCommand = procedurename;

                if (param != null)
                {
                    foreach (PropertyInfo pi in param.GetType().GetProperties())
                    {
                        object pval = pi.GetValue(param, null);
                        if (pval != null)
                        {
                            sds.SelectParameters.Add(pi.Name, pval.ToString());
                        }
                    }
                }

                List<Common.DataObject> results = new List<Common.DataObject>();
                //sds.Select(new DataSourceSelectArguments()).Cast<DataRowView>().ToList().ForEach(o => Load_AddResult<dynamic>(o, ref results));
                sds.Select(new DataSourceSelectArguments()).Cast<DataRowView>().ToList().ForEach(o => Load_AddResult<Common.DataObject>(o, ref results));

                return results;
            }
            catch (Exception ex)
            {
                HandleError_Condensed(ex);
                return null;
            }
        }

        public static void Load_AddResult<t>(Common.DataObject o, ref List<t> results)
        {
            try
            {
                t r = (t)Activator.CreateInstance(typeof(t));

                foreach (PropertyInfo pi in typeof(t).GetProperties())
                {
                    object v = o[pi.Name].ToString();
                    Type pt = Type.GetType(pi.PropertyType.FullName);
                    //try { pi.SetValue(r, Convert.ChangeType(v, pt), null); }
                    //catch (Exception ex) { HandleError_Condensed(ex); }

                    o.Add(pi.Name, Convert.ChangeType(v, pt));
                }

                results.Add(r);
            }
            catch (Exception ex)
            {
                HandleError_Condensed(ex);
            }
        }

        //public static void Load_AddResult<t>(dynamic o, ref List<t> results)
        //{
        //    try
        //    {
        //        t r = (t)Activator.CreateInstance(typeof(t));

        //        foreach (PropertyInfo pi in typeof(t).GetProperties())
        //        {
        //            object v = o[pi.Name].ToString();
        //            Type pt = Type.GetType(pi.PropertyType.FullName);
        //            try { pi.SetValue(r, Convert.ChangeType(v, pt), null); }
        //            catch (Exception ex) { HandleError_Condensed(ex); }
        //        }

        //        results.Add(r);
        //    }
        //    catch (Exception ex)
        //    {
        //        HandleError_Condensed(ex);
        //    }
        //}

        public static void ExecuteNonScalar(string procedurename, dynamic param)
        {
            try
            {
                ExecuteScalar(procedurename, param);
            }
            catch (Exception ex)
            {
                HandleError_Condensed(ex);
            }
        }

        public static int ExecuteScalar(string procedurename, dynamic param)
        {
            try
            {
                SqlDataSource sds = new SqlDataSource();
                sds.ConnectionString = ConfigValues.TrainingPortalConnectionString;
                sds.UpdateCommandType = SqlDataSourceCommandType.StoredProcedure;
                sds.UpdateCommand = procedurename;

                if (param != null)
                {
                    foreach (PropertyInfo pi in param.GetType().GetProperties())
                    {
                        object pval = pi.GetValue(param, null);
                        if (pval != null)
                        {
                            sds.SelectParameters.Add(pi.Name, pval.ToString());
                        }
                    }
                }

                return sds.Update();
            }
            catch (Exception ex)
            {
                HandleError_Condensed(ex);
                return 1; //1 signifies error in tsql
            }
        }
        #endregion

        private static void HandleError_Condensed(Exception ex)
        {
            if (HandleError != null) { HandleError(ex); } else { throw new Exception(ex.Message, ex); } 
        }
    }
}
Advertisement

Custom AWS S3 Helper Class AWSSDK Wrapper

Implements some very commonly used AWS S3 functionality. (need to merge with my other AWS wrapper classes, Route53, EC2, etc)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.IO;
using System.Collections.Specialized;
using System.Configuration;

//uses AWSSDK.dll from amazon
using Amazon;
using Amazon.S3;
using Amazon.S3.Model;

using System.Xml.Linq;
using System.Xml;

using System.Data;

namespace AIS.Common
{
    public static class AWSHelper
    {
        private static List<S3Bucket> LoadS3Buckets()
        {
            System.Collections.Specialized.NameValueCollection appConfig = System.Configuration.ConfigurationManager.AppSettings;
            using (var s3client = Amazon.AWSClientFactory.CreateAmazonS3Client(ConfigValues.AWSAccessKey, ConfigValues.AWSSecretKey))
            {
                return s3client.ListBuckets().Buckets;
            }
        }

        private static List<S3Object> LoadS3Objects(string bucketname)
        {
            System.Collections.Specialized.NameValueCollection appConfig = System.Configuration.ConfigurationManager.AppSettings;
            using (var s3client = Amazon.AWSClientFactory.CreateAmazonS3Client(ConfigValues.AWSAccessKey, ConfigValues.AWSSecretKey))
            {
                return s3client.ListObjects(new ListObjectsRequest() { BucketName = bucketname }).S3Objects;
            }
        }

        private static void LoadS3File(string bucketname, string keyname, HttpResponse response, string contenttype)
        {
            NameValueCollection appConfig = ConfigurationManager.AppSettings;


            using (var s3client = Amazon.AWSClientFactory.CreateAmazonS3Client(ConfigValues.AWSAccessKey, ConfigValues.AWSSecretKey))
            {

                GetObjectRequest s3request = new GetObjectRequest()
                    .WithBucketName(bucketname).WithKey(keyname);

                using (GetObjectResponse s3response = s3client.GetObject(s3request))
                {
                    string title = s3response.Metadata["x-amz-meta-title"];

                    response.Clear();

                    //Response.Write(string.Format("The object's title is {0}", title));
                    //Response.AddHeader
                    //Response.ContentType="application/swf";
                    ////Response.ContentType="contenttype";

                    response.ContentType = s3response.ContentType; //s3response.Headers["Content-Length"];
                    long filesize = s3response.ContentLength;

                    byte[] buffer = new byte[(int)filesize];

                    response.BinaryWrite(ConvertStreamToBytes(s3response.ResponseStream, filesize));

                    response.Flush();
                    response.Close();
                }
            }
        }

        public static string GetS3UrlToVideo(string bucketname, string keyname)
        {
            System.Collections.Specialized.NameValueCollection appConfig = System.Configuration.ConfigurationManager.AppSettings;
            string url = "";
            using (var s3client = Amazon.AWSClientFactory.CreateAmazonS3Client(ConfigValues.AWSAccessKey, ConfigValues.AWSSecretKey))
            {
                Amazon.S3.Model.GetPreSignedUrlRequest request = new Amazon.S3.Model.GetPreSignedUrlRequest()
                    .WithBucketName(bucketname)
                    .WithKey(keyname)
                    .WithProtocol(Amazon.S3.Model.Protocol.HTTP)
                    .WithVerb(HttpVerb.GET)
                .WithExpires(DateTime.Now.AddMinutes(ConfigValues.VideoURLExpiration));

                Amazon.S3.Model.GetPreSignedUrlRequest r = new GetPreSignedUrlRequest();

                url = s3client.GetPreSignedURL(request);

                url= "https://s3.amazonaws.com/" + bucketname + keyname;
            }

            //return System.Xml.XmlConvert.EncodeName(url);
            return url;
        }

        public static byte[] ConvertStreamToBytes(Stream input, long filesize)
        {
            byte[] buffer = new byte[(int)filesize];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                return ms.ToArray();
            }
        }
    }
}

Custom Web.Config Wrapper Class ASP .NET

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;

namespace AIS.Common
{
    public class ConfigValues
    {
        #region appSettings
        public static string SomeStringOne { get { return getval("SomeStringOne "); } }
        public static string SomeStringTwo { get { return getval("SomeStringTwo "); } }
        public static string Env { get { return getval("env"); } } //keep in mind case sensitivity
        public static string LastManualRefresh { get { return getval("date_last_manual_refresh"); } } //useful for manual site refresh/reload
        public static double SomeDouble { get { return Convert.ToDouble(getval("some_static_double")); } }
        #endregion

        #region connectionStrings - update web.config env variable to toggle between dev and prd
        public static string YourDBOneConnectionString { get { return getcstr("win_web_db"); } }

//also read only implementation like above, but illustrates environment variable usage specific in web.config useful if you have many environments
        public static string YourDBTwoConnectionString 
        {
            get
            {
                if (Env.ToLower().ToString() != "filesystem")
                {
                    return getcstr("static_string" + Env.ToLower().ToString());
                }
                return "";
            }
        }
        #endregion

        /// <summary>
        /// Retrieve Connection String for specified provided key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private static string getcstr(string key)
        {
            try
            {
                return ConfigurationManager.ConnectionStrings[key].ConnectionString;
            }
            catch (Exception ex)
            {
                Shared.HandleError(ex); //TODO: change to throw error event handle instead of direct call for reusability
                return "Error retrieving value";
            }
        }

        /// <summary>
        /// Retrieve appSettings value for provided specified key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private static string getval(string key)
        {
            try
            {
                return ConfigurationManager.AppSettings[key];
            }
            catch (Exception ex)
            {
                Shared.HandleError(ex); //TODO: change to throw error event handle instead of direct call for reusability
                return "Error retrieving value";
            }
        }
    }
}

Custom URLRewriting with XML and Global.asax

utilizes my custom DocParser class here https://ronniediaz.com/2013/08/23/parse-xml-to-dynamic-expandoobject-c-net-4-0/

 void Application_BeginRequest(object sender, EventArgs e)
    {
        //string path = Request.Url.ToString();
        string path = Request.Path;

        if (Regex.IsMatch(path.ToLower(), ".*[.](jpg|png|gif|css|js|pdf|ico|woff|svg|eot|ttf)$"))
        {
            //var h = Regex.Replace(path.ToLower(), ".*/(.*)/(.*)$", "~/$1/$2", RegexOptions.Singleline);
            //Context.RewritePath(path);
            return;
        }
        
        //TODO: authorize user/request
 DocParser dp = new DocParser(Server.MapPath("~/rewrite.xml"));
        var rules = dp.GetElements("*/rule");
        
        foreach (var r in rules)
        {
            if (string.IsNullOrEmpty(r.match_url)) {
                Shared.HandleError("Global.asax::null or empty match_url encountered");
            }

            if (string.IsNullOrEmpty(r.action_url))
            {
                Shared.HandleError("Global.asax::null or empty action_url encountered");
            }
            
            if (Regex.IsMatch(path, r.match_url,RegexOptions.IgnoreCase))
            {
                List<object> qsvars = new List<object>();

                foreach (Match m in Regex.Matches(path, r.match_url, RegexOptions.IgnoreCase))
                {
                    for (int i=1;i<m.Groups.Count;i++)
                    {
                        qsvars.Add(m.Groups[i].Value);
                    }
                }
                //Context.RewritePath(string.Format(r.action_url,qsvars.ToArray()) + "&rewrite=1");
                Context.RewritePath(string.Format(r.action_url, qsvars.ToArray()));
            }
        }
}

rewrite.xml examples

<?xml version="1.0" encoding="utf-8" ?>
<rules>
  <rule match_url="^/home" action_url="~/home.aspx" />
  <rule match_url="^/login" action_url="~/default.aspx" />
  <rule match_url="^/register" action_url="~/welcome/register.aspx" />
  <rule match_url="^/logout" action_url="~/logout.aspx" />
  <rule match_url="^/default/(.*)" action_url="~/default.aspx?q={0}" />
  <rule match_url="^/test/(.*)/(.*)" action_url="~/test.aspx?q={0}&amp;r={1}" />
</rules>

asp .net grid control common gridview operations update edit cancel sort paging

There are many ways to accomplish the end result of what is displayed below.

To display multiple records of data on the same page, you may alternatively use Repeater (my favorite of the dataview controls), DataList or ListView (also great).

FormView and DetailsView are similar, but should be limited to smaller sets of data IMO or in a system where limited results are only displayed in this control after selection from a search or query filter.

The control on the HTML design side:

<asp:UpdatePanel ID="upnlContent" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="false">
            <ContentTemplate>
  <div id="modal" style="display: none;" title="Application Message">
                    <asp:Label ID="lblError" runat="server"></asp:Label>
                </div>
<asp:GridView ID="gvDataList" runat="server" AllowPaging="True" OnRowEditing="gvDataList_EditRecord"
                        OnRowCancelingEdit="gvDataList_CancelRecord" OnRowUpdating="gvDataList_UpdateRecord"
                        AutoGenerateColumns="False" AllowSorting="true" PageSize="50" DataKeyNames="TreeID"
                        OnRowCommand="gvDataList_RowCommand" OnSorting="gvDataList_Sorting" OnPageIndexChanging="gvDataList_PageIndexChanging">
                        <AlternatingRowStyle BackColor="#EFEFEF" />
                        <Columns>
                            <asp:BoundField DataField="TreeID" HeaderText="TreeID" InsertVisible="False" SortExpression="TreeID"
                                ReadOnly="True" />
                            <asp:TemplateField HeaderText="ActiveStatus" SortExpression="ActiveStatus">
                                <ItemTemplate>
                                    <asp:Label ID="lblActiveStatus" runat="server" Text='<%# Eval("ActiveStatus")%>'></asp:Label>
                                </ItemTemplate>
                                <EditItemTemplate>
                                    <asp:CheckBox ID="chkActiveStatus" runat="server" Checked='<%# Convert.ToBoolean(Eval("ActiveStatus")) %>'
                                        Enabled='<%# GetEditPermission("activestatus") %>' />
                                </EditItemTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField HeaderText="Name" SortExpression="Name">
                                <ItemTemplate>
                                    <asp:HyperLink ID="Name" runat="server" NavigateUrl='<%# "~/Pages/ExistingOrange.aspx?TreeID=" + Eval("TreeID")%>'>
                        <%# Eval("Name")%>
                                    </asp:HyperLink>
                                </ItemTemplate>
                                <EditItemTemplate>
                                    <asp:TextBox ID="tbtreename" runat="server" Text='<%# Eval("Name") %>' />
                                </EditItemTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField HeaderText="Description" SortExpression="Description">
                                <ItemTemplate>
                                    <asp:HyperLink ID="hltreedescription" runat="server" NavigateUrl='<%# "~/Pages/ExistingOrange.aspx?TreeID=" + Eval("TreeID")%>'>
                        <%# Eval("Description")%>
                                    </asp:HyperLink>
                                </ItemTemplate>
                                <EditItemTemplate>
                                    <asp:TextBox ID="tbtreedescription" runat="server" Text='<%# Eval("Description") %>' />
                                </EditItemTemplate>
                            </asp:TemplateField>
                            <asp:TemplateField HeaderText="Country" SortExpression="CountryID" ItemStyle-HorizontalAlign="Center">
                                <ItemTemplate>
                                    <asp:Label ID="lblCountryID" runat="server" Text='<%# getcountryname(Eval("CountryID"))%>'></asp:Label>
                                </ItemTemplate>
                                <EditItemTemplate>
                                    <asp:DropDownList ID="ddlCountryID" runat="server" Enabled='<%# GetEditPermission("allowregion") %>'
                                        DataSource='<%# countriesdropdown %>' DataTextField='Description' DataValueField="CountryID" />
                                </EditItemTemplate>
                            </asp:TemplateField>
                            <asp:BoundField DataField="LastUpdated" HeaderText="Last Updated" SortExpression="LastUpdated"
                                ReadOnly="true" />
                            <asp:BoundField DataField="ExpirationDate" HeaderText="Expiration Date" InsertVisible="False"
                                SortExpression="ExpirationDate" ReadOnly="True" />
                            <asp:BoundField DataField="runcount" HeaderText="Pick Count" InsertVisible="False"
                                SortExpression="PickCount" ReadOnly="True" />
                            <asp:CommandField ButtonType="Button" EditText="Edit" UpdateText="Update" CancelText="Cancel"
                                HeaderText="Edit Row" ShowEditButton="true" />
                            <asp:ButtonField CommandName="NewOrange" ButtonType="Button" Text="Create" HeaderText="New Orange" />
                        </Columns>
                    </asp:GridView>
            </ContentTemplate>
        </asp:UpdatePanel>

The Events and functions attached to the control on the code behind side:

 private void LoadData(string sort, bool asc)
        {
            DAL.AC_DataClassesDataContext dc = new DAL.AC_DataClassesDataContext();
            var data = (from Trees in dc.Trees
                        join Oranges in dc.Oranges on new { TreeID = Trees.TreeID } equals new { TreeID = Convert.ToInt32(Oranges.TreeID) } into Oranges_join
                        from Oranges in Oranges_join.DefaultIfEmpty()
                        group new { Oranges, Trees } by new
                        {
                            Trees.TreeID,
                            Trees.ActiveStatus,
                            Trees.Name,
                            Trees.Description,
                            Trees.CountryID,
                            Trees.LastUpdated
                        } into g
                        select new
                        {
                            TreeID = (System.Int32?)g.Key.TreeID,
                            ExpirationDate = (System.DateTime?)g.Max(p => p.Oranges.PickDate),
                            PickCount = g.Count(),
                            ActiveStatus = (System.Byte?)g.Key.ActiveStatus,
                            g.Key.Name,
                            g.Key.Description,
                            g.Key.CountryID,
                            LastUpdated = (System.DateTime?)g.Key.LastUpdated
                        });

            data = data.OrderByField(sort, asc); //OrderByField uses dynamic linq library which is a free additional open source download from MS

                try
                {
                    data = data.Where(g => g.TreeID == Convert.ToInt32(ddlTreeIDs.SelectedValue));
                }
                catch (Exception ex)
                {
                    lblError.Text = ex.ToString();
                    utils.ShowJQueryModal(this, ex); //static custom class I created to show dialog containing lblerror text
                }

            gvDataList.DataSource = data;
            gvDataList.DataBind();
            upnlContent.Update();
        }

        protected void gvDataList_RowCommand(object sender, GridViewCommandEventArgs e)
        {
            if (e.CommandName == "NewOrange")
            {
                string redirecturl = "~/Pages/NewOrange.aspx?TreeID={0}"; //this page should be pretty self explanatory
                string TreeID = (((GridView)sender).Rows[Convert.ToInt32(e.CommandArgument)].Cells[0]).Text;
                redirecturl = String.Format(redirecturl, TreeID);
                Response.Redirect(redirecturl);
            }
        }

		//example of a mechanism that can be used to change style or visibility of controls specific to user access
        public bool GetEditPermission(string permtype)
        {
            switch (permtype.ToLower())
            {
                case "other":
                    if (utils.usergroup == "admin")
                    {
                        return true;
                    }
                    else return false;
                case "allowregion":
                    if (utils.usergroup == "admin")
                    {
                        return true;
                    }
                    else return false;
                default:
                    return true;
            }
        }

        protected void gvDataList_UpdateRecord(object sender, GridViewUpdateEventArgs e)
        {
            DAL.AC_DataClassesDataContext dc = new DAL.AC_DataClassesDataContext();

            int TreeID, activestatus, CountryID;
            string Name, Description;

            try
            {
                TreeID = Convert.ToInt32(e.Keys[0]); //should be 0
                activestatus = Convert.ToInt32(((CheckBox)gvDataList.Rows[e.RowIndex].FindControl("chkActiveStatus")).Checked);
                Name = Convert.ToString(((TextBox)gvDataList.Rows[e.RowIndex].FindControl("tbName")).Text);
                Description = Convert.ToString(((TextBox)gvDataList.Rows[e.RowIndex].FindControl("tbDescription")).Text);
                CountryID = Convert.ToInt32(((DropDownList)gvDataList.Rows[e.RowIndex].FindControl("ddlCountryID")).SelectedValue);
            }
            catch (Exception ex)
            {
                //throw new Exception("Error retrieving grid values for update.");
                lblError.Text = "Error retrieving grid values for update. Details: " + ex.ToString();
                utils.ShowJQueryModal(this);
                upnlContent.Update();
                return; //unassigned local variables if this is skipped or exception now thrown
            }

            int result = dc.ExecuteCommand("update Trees set ActiveStatus={1}," +
           "Name={2},Description={3}," +
           "CountryID={4} where TreeID={0}",
                      TreeID, activestatus, Name, Description,
                      CountryID);

            if (result == 1)
            {
            }
            else
            {
                lblError.Text = "Record failed to update.";
                utils.ShowJQueryModal(this); //static custom class I created to show modal dialog containing lblerror text
            }
            gvDataList.EditIndex = -1;
            LoadData();
        }

        protected void gvDataList_EditRecord(object sender, GridViewEditEventArgs e)
        {
            gvDataList.EditIndex = e.NewEditIndex;
            LoadData();
        }

        protected void gvDataList_CancelRecord(object sender, GridViewCancelEditEventArgs e)
        {
            gvDataList.EditIndex = -1;
            LoadData();
        }

        private string ConvertSortDirectionToSql(SortDirection sortDirection)
        {
            string newSortDirection = String.Empty;

            switch (sortDirection)
            {
                case SortDirection.Ascending:
                    newSortDirection = "ASC";
                    break;

                case SortDirection.Descending:
                    newSortDirection = "DESC";
                    break;
            }

            return newSortDirection;
        }

        protected void gvDataList_PageIndexChanging(object sender, GridViewPageEventArgs e)
        {
            gvDataList.PageIndex = e.NewPageIndex;
            gvDataList.DataBind();
        }

        protected void gvDataList_Sorting(object sender, GridViewSortEventArgs e)
        {

            bool asc = true; //default to true per usual .net behavior
            if (ViewState[e.SortExpression] != null)
            {
                asc = (!(bool)ViewState[e.SortExpression]);
                ViewState[e.SortExpression] = asc;
            }
            else
            {
                ViewState[e.SortExpression] = true;
            }

            LoadData(e.SortExpression, asc);
        }

        //Show modal dialog using jquery. Requires javascript reference/link to jquery in the page.
        public static void ShowJQueryModal(Page PageInstance, Exception ex)
        {
            ClientScriptManager ClientScript = PageInstance.ClientScript;
            AjaxControlToolkit.ToolkitScriptManager.RegisterStartupScript(PageInstance, PageInstance.GetType(), "preparemodal",
                "<script type=\"text/javascript\">$('#modal').dialog({autoOpen: false, modal: true });</script>", false);
            AjaxControlToolkit.ToolkitScriptManager.RegisterStartupScript(PageInstance, PageInstance.GetType(), "loadmodal",
                "<script type=\"text/javascript\">$('#modal').dialog('open');</script>", false);
        }

Links and references to Dynamic LINQ may change over time (no pun intended).

At the time of writing this they can be found on MS and Scott Gu’s blog. If you cannot find it, send me an email and I can send it to you or you can refer to my post on OrderBy Column Name for the exact extension method.

lastChild is null in FireFox works in IE invalid nodeType javascript c# asp .net

This issue alluded me at first as it works in IE but not in FF. See code below.

//pass in table, last cell number and style to apply to it. call this on hover and blur for cell highlight effects. alternatively you can determine last cell number as well and this function could be rewritten to work solely for the purpose of modifying specific cells rather than last cell
function ChangeTableCellStyle(tableid,cellnumber,mystyle) {
if (document.getElementById)
{
var selectedElement = document.getElementById(tableid);
selectedElement.className = style;
//change style on end cell by drilling into table. this will become deprecated by css3.
if (selectedElement.tagName.toLowerCase()=="table")
{

var tbody = selectedElement.lastChild;
if (tbody!=null)
{
var tr = tbody.lastChild;
if (tbody !=null)
{
var tr = tbody.lastChild; //BUGGED IN FF!

//nodetype should be 1 for element type. in FF it is 3. see reference link at bottom for list of types.
if (tr.nodeType!=1) {
tr.tbody.getElementsByTagName("td");
tr[cellnumber].className+= ' ' + mystyle;
} else {
tr.lastChild.className+=' ' + mystyle;
}

}
}

}
}

}

//example usage
ChangeTableCellStyle("table1",3,"cellend"); //will append the class cellend to the last cell in table1 if table1 only has 4 cells per row

In you’re interested in reviewing other approaches to styling your table cells, see my similar article here.

C# ListBox Management Adding Removing Updating Databound Items ASP .Net

The lambda one-liner indicated in the snippet below essentially nests at least two “for/foreach” loops. See my related article for full source.

This code snippet is used to populate a drop down list of all factories containing unregistered robots where are not already marked in the list to be decommissioned.

Upon selecting a factory containing unregistered robots, another listbox is populated with the robots so they can be selected from which moves them into the decommissioned list.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Configuration;

public partial class DecommissionRobots : System.Web.UI.UserControl
{
public event EventHandler SendToDecommission;

    public void Update()
    {
        upnlContainer.Update();
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            LoadRegions();
            txtExpDate_CalendarExtender.SelectedDate = DateTime.UtcNow.AddMonths(6);
        }
    }

    protected void LoadRegions()
    {
        using (AndroneticsDataContext db = new TigrentLearningDataContext(
        ConfigurationManager.ConnectionStrings["AndroneticsConnection1"].ConnectionString)) {
        ddlRegions.DataSource = db.UP_GET_REGIONS();
        ddlRegions.DataTextField = "REGION";
        ddlRegions.DataValueField = "REGION_ID";
        ddlRegions.DataBind();

        ListItem li = new ListItem("", "");
        ddlRegions.Items.Insert(0, li);
}
    }

    protected void ClearLists()
    {
        lstUnselectedRobots.Items.Clear();
//you may want to clear other lists in this manner in your app as well
    }

protected void LoadFactories()
    {
        ClearLists();

        if (ddlSegment.SelectedIndex > 0)
        {
            using (AndroneticsDataContext db = new AndroneticsDataContext(
        ConfigurationManager.ConnectionStrings["AndroneticsConnection1"].ConnectionString))
            {
                List<UP_GET_FactoriesResult> allFactories = db.UP_GET_Factories(Convert.ToInt32(ddlRegion.SelectedValue), null).ToList();

                ////this would be approximately how you would approach traditionally
                //foreach (UP_GET_FactoriesResult r in allFactories)
                //{
                //    if (GetUnregisteredRobots(r.FACTORY_ID).Count != 0)
                //    {
                //        //etc, would need another loop here
                //    }
                //}

                //now for the lambda way
                var Factories = allFactories.Where(
                    r => GetUnregisteredRobots(r.FACTORY_ID).Where(
                        ra => !lstDecommissionRobots.Items.Contains(new ListItem(ra.ROBOT_NAME,ra.ROBOT_ID.ToString()))).Count() != 0);

                ddlFactories.DataSource = Factories;
                ddlFactories.DataTextField = "FACOTRY_TITLE";
                ddlFactories.DataValueField = "FACTORY_ID";
                ddlFactories.DataBind();

                ListItem li = new ListItem("", "");
                ddlFactories.Items.Insert(0, li);
            }
        }
    }

    private List<UP_LOAD_COURSE_RobotsResult> GetUnregisteredRobots(int courseid)
    {
        using (AndroneticsDataContext db = new AndroneticsDataContext(
        ConfigurationManager.ConnectionStrings["AndroneticsConnection1"].ConnectionString))
        {
            List<UP_LOAD_COURSE_RobotsResult> allRobots = db.UP_LOAD_COURSE_Robots(courseid).ToList();

            int userID = int.Parse(Request.QueryString["ID"]);
            List<string> excregisteredRobots = (from m in db.UP_GET_REGISTERED_Robots(userID) select m.MODULE_NAME).ToList();

            return allRobots.Where(m => !excregisteredRobots.Contains(m.MODULE_NAME)).ToList();
        }
    }

protected void LoadUnregisteredRobots()
    {
        lstUnselectedRobots.Items.Clear();

        //we need to make sure a re=d-g.and FACTORY were selected.
        if (ddlFactories.SelectedIndex > 0 && ddlRegion.SelectedIndex > 0)
        {
//notice this reuses the same code as above any simple retrieves the results for value selected in the dropdown. this value is updated by autopostback true set on the aspx page side.
            lstUnselectedRobots.DataSource = GetUnregisteredRobots(Convert.ToInt32(ddlFactories.SelectedValue));
            lstUnselectedRobots.DataTextField = "Robot_NAME";
            lstUnselectedRobots.DataValueField = "Robot_ID";

            lstUnselectedRobots.DataBind();
        }
    }

protected void btnSelect_Click(object sender, ImageClickEventArgs e)
    {
        List<ListItem> selectedItems = new List<ListItem>();

        //add all the selected items to a list
        foreach (ListItem li in lstSelectItems.Items)
        {
            if (li.Selected)
            {
                selectedItems.Add(li);
            }
        }

        //add the selected items to the selected box
        lstSelectedItems.Items.AddRange(selectedItems.ToArray());

        //remove the selected items from the original list
        foreach (ListItem items in selectedItems)
        {
            lstUnselectedRobots.Items.Remove(items);
        }

        LoadFactories();
    }

    protected void btnRemove_Click(object sender, ImageClickEventArgs e)
    {
        List<ListItem> selectedItems = new List<ListItem>();

        //add all the selected items to a list
        foreach (ListItem li in lstSelectedItems.Items)
        {
            if (li.Selected)
            {
                lstDecommissionRobots.Add(li);
            }
        }

        //add the selected items back to the initial selection box
        lstUnselectedRobots.Items.AddRange(selectedItems.ToArray());

        //remove the selected items from the selected list
        foreach (ListItem items in selectedItems)
        {
            lstDecommissionRobots.Items.Remove(items);
        }

        LoadFactories();
    }

    protected void btnSend_Click(object sender, ImageClickEventArgs e)
    {
        List<USER_ACCESS> FactoryItems = new List<USER_ACCESS>();
        int userid= int.Parse(Session["userid"].ToString());

        try
        {
            if (lstDecommissionRobots.Items.Count > 0)
            {
                //for each Factory item that's selected, add it to the Factory list
                foreach (ListItem li in lstDecommissionRobots.Items)
                {
                    USER_ACCESS regFactory = new USER_ACCESS()
                    {
                        USER_ID = studentID,
                        Robot_ID = Convert.ToInt32(li.Value),
                        EXPIRATION_DATE = Convert.ToDateTime(txtExpDate.Text),
                        CREATED_BY = Users.CurrentUser.UserID.ToString()
                    };

                    FactoryItems.Add(regFactory);
                }

                //Make sure the list got filled and then insert the Factories into the db.
                if (FactoryItems.Count > 0)
                {
                    AndroneticsDAL dalInstance = new AndroneticsDAL();
                    dalInstance.EnrollStudent(FactoryItems);

                    //TODO: replace with update event handle
                    //PopulateFactories(userid);
                    ClearLists();
                    lstDecommissionRobots.Items.Clear();
                    ddlSegment.ClearSelection();
                    ddlFactories.ClearSelection();

                    if (SendToDecommission != null)
                    {
                        SendToDecommission(sender,e);
                    }
                }
            }
            else
            {
                //PopulateFactories(userid);
            }
        }
        catch (Exception ex)
        {
//Utility.HandleError(ex); //send to email, handle, etc or handle in global.asax
        }
    }

    protected void ddlRegion_SelectedIndexChanged(object sender, EventArgs e)
    {
        LoadFactories();
        ddlFactories.SelectedItem.Selected = false;
    }

    protected void ddlFactories_SelectedIndexChanged(object sender, EventArgs e)
    {
        LoadRobots();
    }
}

HTML/ASPX Side:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="DecommissionRobots.ascx.cs" Inherits="DecommissionRobots" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<asp:UpdatePanel ID="upnlContent" runat="server" ChildrenAsTriggers="false"
            UpdateMode="Conditional">
            <ContentTemplate>
                <asp:Panel runat="server" ID="pnlFactorieselection" GroupingText="Decommission Robots">
                    <div class="panelPadding paddingTop10 tableSize">
                        <div>
                            <div class="displayInlineLeftFloat labelSize">
                                <asp:Label runat="server" ID="lblRegion" AssociatedControlID="ddlRegion" Text="Region Name:"
                                    CssClass="labelSize"></asp:Label></div>
                            <div class="displayInlineLeftFloat FactoryDropDowns">
                                <asp:DropDownList runat="server" ID="ddlRegion" AutoPostBack="true" OnSelectedIndexChanged="ddlRegion_SelectedIndexChanged">
                                    <asp:ListItem Text="United States" Value="UnitedStats"></asp:ListItem>
                                    <asp:ListItem Text="United Kingdom" Value="UnitedKingdom"></asp:ListItem>
                                </asp:DropDownList>
                            </div>
                        </div>
                        <div class="clearFloat paddingTop10">
                            <div class="displayInlineLeftFloat labelSize">
                                <asp:Label runat="server" ID="lblFactories" AssociatedControlID="ddlFactories" Text="Factory Name:"
                                    CssClass="labelSize"></asp:Label></div>
                            <div class="displayInlineLeftFloat FactoryDropDowns">
                                <asp:DropDownList runat="server" ID="ddlFactories" AutoPostBack="true" OnSelectedIndexChanged="ddlFactories_SelectedIndexChanged">
                                </asp:DropDownList>
                            </div>
                        </div>
                        <div class="clearFloat paddingTop10">
                            <div class="displayInlineLeftFloat labelSize">
                                <asp:Label runat="server" ID="lblExpDate" AssociatedControlID="txtExpDate" Text="Expiration Date:"
                                    CssClass="labelSize"></asp:Label></div>
                            <div class="displayInlineLeftFloat">
                                <asp:TextBox runat="server" ID="txtExpDate"></asp:TextBox>
                                <asp:CalendarExtender ID="txtExpDate_CalendarExtender" runat="server" DefaultView="Months"
                                    Enabled="True" TargetControlID="txtExpDate">
                                </asp:CalendarExtender>
                            </div>
                        </div>
                        <div class="clearFloat">
                            <br />
                        </div>
                        <div>
                            <div>
                                <span class="listWidth displayInline CenterElement">Unregistered Robots</span><span
                                    id="selectedCaption" class="listWidth displayInline CenterElement">Selected
                                    Robots</span></div>
                            <div id="RegSection" class="displayInlineLeftFloat">
                                <asp:ListBox ID="lstUnregisteredRobots" runat="server" CssClass="FloatLeft listWidth" Rows="10"
                                    SelectionMode="Multiple"></asp:ListBox>
                                <div id="selectButtons" class="floatContainer">
                                    <div>
                                        <asp:ImageButton runat="server" ID="btnSelect" AlternateText="select" OnClick="btnSelect_Click"
                                            ImageUrl="~/Images/special_right.gif" /></div>
                                    <div class="buttonTopMargin5">
                                        <asp:ImageButton runat="server" ID="btnRemove" AlternateText="remove" ImageUrl="~/Images/special_left.gif"
                                            OnClick="btnRemove_Click" /></div>
                                </div>
                                <asp:ListBox runat="server" ID="lstDecommissionRobots" Rows="10" SelectionMode="Multiple"
                                    CssClass="listWidth"></asp:ListBox>
                            </div>
                            <div id="sendButton">
                                <asp:ImageButton runat="server" ID="btnSend" AlternateText="Enroll" ImageUrl="~/Images/btn_send.gif"
                                    OnClick="btnSend_Click" /></div>
                        </div>
                    </div>
                </asp:Panel>
            </ContentTemplate>
            <Triggers>
                <asp:AsyncPostBackTrigger ControlID="ddlRegion" EventName="SelectedIndexChanged" />
                <asp:AsyncPostBackTrigger ControlID="ddlFactories" EventName="SelectedIndexChanged" />
                <asp:AsyncPostBackTrigger ControlID="btnSelect" EventName="Click" />
                <asp:AsyncPostBackTrigger ControlID="btnRemove" EventName="Click" />
                <asp:AsyncPostBackTrigger ControlID="btnSend" EventName="Click" />
            </Triggers>
        </asp:UpdatePanel>

References
Fraction Of The Blogosphere, https://ronniediaz.com/2010/12/21/lambda_functions_in_-net/

C# Event Handlers and Delegates in ASP .Net with Web User Controls

This article should help as a general how to on event handlers and delegates in C# as well as propose a different way to handle cross page methods in your ASP .Net website from a web user control or other page.

Dilemma:
Page contains user control which has some methods and functionality built in. When a particular button click or other generic event is fired in the user control, it needs to call back to the parent page.

Solution:
Create event handlers and their delegates in the user control, fire them from the methods tied to the internal controls protected events, and define the methods that will handle the new events in the page (see code below).

C# (with some VB notes):

//delegate declaration not necessary in VB
 public delegate void MyCustomHandler(object sender, EventArgs e);
    public event MyCustomHandler SomethingClicked;

    protected void btnButton1_Click(object sender, EventArgs e)
    {
//tell our parent page which is listening for the event that something was clicked
//this null check and method invoke is the equivalent of raise event in VB
        if (SomethingClicked != null)
        {
            SomethingClicked(sender, e);
        }

//do some other work specific to this button in the user control
    }


That’s the code for your user control, now for the page.

 protected void Page_Load(object sender, EventArgs e)
    {

        MyUserControl1.SomethingClicked += new MyUserControl1.MyCustomHandler(MyUserControl1_SomethingClicked);
        

        if (!Page.IsPostBack)
        {
            //do my other normal work
        }

    }

    protected void MyUserControl1_SomethingClicked(object sender, EventArgs e)
    {
//voila! clicking on the button in your user control will fire this method on the parent page!
    }

Alternatively instead of declaring your own delegate, you can also simply use:

//in control
public event EventHandler SomethingClicked;

//and in page load
MyUserControl1.SomethingClicked+= new EventHandler(MyUserControl1_SomethingClicked);

If you have no need for custom arguments, this a good quick alternative that may be well liked by VB users where delegate declaration is optional.

References
DeveloperFusion, http://www.developerfusion.com/article/2137/event-handling-in-net-using-c/3/
VBForums, http://www.vbforums.com/showthread.php?t=521089
MSDN (events and delegates), http://msdn.microsoft.com/en-us/library/17sde2xt%28v=vs.71%29.aspx
MSDN (dynamically bind event handlers), http://msdn.microsoft.com/en-us/library/t3d01ft1%28v=vs.80%29.aspx
MSDN (which control raised an event), http://msdn.microsoft.com/en-us/library/zk6b17bs%28v=vs.80%29.aspx
ASP.Net (blog), http://weblogs.asp.net/rweigelt/archive/2005/01/14/353333.aspx
TechRepublic, http://www.techrepublic.com/article/simplify-net-class-communication-with-delegates/1050214
Akadia, http://www.akadia.com/services/dotnet_delegates_and_events.html

C# Nested Repeaters ASP .Net

Nested repeaters are a very common topic in ASP .Net so I thought it would be a good subject to write on, especially considering the number of solutions that exist when you Google “nested repeaters” that offer plug-and-play answers, but don’t actually explain why one approach may be more optimal than another.

The Solution

XML/HTML for your repeaters:

<asp:Repeater runat="server" ID="rptRobotFactories" EnableViewState="false" OnItemDataBound="rptRobotFactories_ItemDataBound">
                        <ItemTemplate>
                            <div id="header">
                                <%# (((System.Data.DataRowView)Container.DataItem)["FACTORYNAME"]) %>
                            </div>
                            <asp:Repeater runat="server" ID="rptRobots" EnableViewState="false">
                                <HeaderTemplate>
                                    <ul>
                                </HeaderTemplate>
                                <ItemTemplate>
                                    <li>
                                        <%# Eval("ROBOTNAME") %>
                                    </li>
                                </ItemTemplate>
                                <FooterTemplate>
                                    </ul></FooterTemplate>
                            </asp:Repeater>
                        </ItemTemplate>
                    </asp:Repeater>

Code-behind to load data into rptRobotFactories:

//don't forget these guys. save the practice on your typing, finger joints will thank you later =)
using System.Data;
using System.Data.SqlClient;

//a few more variables than necessary were used for code readability. feel free to condense.
//call this function on page load. don't forget your if not postback check
    private void LoadFactories()
    {
        //don't forget to wrap in your exception handling!

          SqlConnection conn = new SqlConnection(
            ConfigurationManager.ConnectionStrings["RobotDBCon"].ConnectionString);

        SqlDataAdapter da = new SqlDataAdapter();
        SqlCommand cmd = new SqlCommand("SP_GET_ROBOTS_IN_FACTORIES", conn);

        cmd.CommandType = CommandType.StoredProcedure;
        //generally you'd probably have some parameters here

        da.SelectCommand = cmd;

        DataTable dtRobots = new DataTable("robots"); //first we get the robots
        
        da.Fill(dtRobots); //notice there's only one SP call and one datatable filled

//this might seem strange using a string array for columns, but the alternative is not as clean IMO
        string[] cols = new string[1]; //if you're uncomfortable using string as primary key add another column and use ID
        cols[0] = "FACTORYNAME";

//these next two lines are the magic makers
        DataTable dtRobotFactories = dtRobots.DefaultView.ToTable("robotfactories", true, cols).Clone();

        dtRobots.DefaultView.ToTable("robotfactories", true, cols).AsEnumerable().Distinct().CopyToDataTable(dtRobotFactories, LoadOption.OverwriteChanges);

        DataSet ds = new DataSet();
        ds.Tables.Add(dtRobotFactories);
        ds.Tables.Add(dtRobots);
       ds.Relations.Add("robotsinfactories",
ds.Tables["robotfactories"].Columns["FACTORYNAME"],
ds.Tables["robots"].Columns["FACTORYNAME"],false);
        ds.Relations[0].Nested = true;

        rptSegments.DataSource = ds.Tables["robotfactories"];
        rptSegments.DataBind();

        conn.Close();
    }

Last piece of code is our itemdatabound event of the parent repeater which loads the child data. Alternatively you can put this inline as the datasource property with a one liner but this approach may allow you more flexibility later:

    protected void rptRobotFactories_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        if ((e.Item.ItemType == ListItemType.Item) || (e.Item.ItemType == ListItemType.AlternatingItem))
        {
            Repeater rptRobots = (Repeater)e.Item.FindControl("rptRobots");
            rptRobots.DataSource = ((DataRowView)e.Item.DataItem).CreateChildView("robotsinfactories");
            rptRobots.DataBind();
        }
    }

And that’s it! Your result should look something like:

FACTORY1
 *ROBOTA1
 *ROBOTA2
FACTORY2
 *ROBOTB1
 *ROBOTB2

What makes this code different?

The use of data relations is disputable. Rightfully arguable, depending on the scope of your project and the data being returned and formatted, this may be overkill.

Multiple data relations and tables can use excess resources when simple string variables could be pulled from the dataset and the same achieved with only one repeater or listview.

I do not contest this point but keep in a mind, a simple re-usable design pattern can be rapidly applied to many different sets of data, whereas a customized variable or array based solution will likely be specific to your initial implementation, and not easily re-adapted in another page or separate project.

Ultimately, code patterns will improve your code readability and productivity as a developer.

See my article on how to create secure relational databases in sql for more information on why the result should come back in a single stored procedure rather than making multiple calls.

Calendar Extender Highlight Current Day in C# .Net

Thanks goes to Karan from asp.net blogs.

 <asp:CalendarExtender ID="CalendarExtender1" runat="server" TargetControlID="tbTarget1"
                                PopupButtonID="btnCalendar" CssClass="calendarposition" OnClientShowing="currentdateactive">
                            </asp:CalendarExtender>
    function currentdateactive(e) {
        if (!e.get_selectedDate() || !e.get_element().value)
            e._selectedDate = (new Date()).getDateOnly();
    }
.ajax__calendar_active{background-color:#820024;color:#ffffff;border:1px solid #D4D0C8;}

/*use your own class to control positioning. careful of nested relative/absolute divs*/
.calendarposition{position:absolute;margin-top:250px;margin-left:250px;background-color:#fff;border:1px solid silver;}

/*prepend css class with div to override ms ajax web.resx autogenerated css*/
div.ajax__calendar_day{text-align:center;}

References
ASP.Net (blogs), http://weblogs.asp.net/karan/archive/2010/09/20/calendar-extender-today-s-date.aspx