Recurring Events in ASP.NET

November 12, 2008 09:49 by John M

So I had some trouble finding a good way on how to create a recurring event in asp.net.  After playing around for a bit this is the concept I came up with and it worked quite well. The biggest date range I tested was about 12 months worth.  I was worried about how many iterations this concept would use, but turned out it wasn't that bad.

You figure the average user will have a recurring event 2-3 days a week and at the most 12 months worth. With the method below it would create about a total of 1090 iterations.  This would cause for about 145 DB entries (if you store each event as a seperate record).  Their are different ways to store the events, but I am doing a seperate record right now just because I don't want to have to touch the backend of the DB I'm working with (yes I know poor excuse).

Their isn't any performance hit for this so far.  Then again I don't have it writing to the DB yet either. So with that said if anyone else can come up with a more efficient concept please let me know.


Concept

Have user choose which days of the week the event is on
Have user choose time of the event
Have user choose a date range for the events recurrence

Store event information in a struct
Store the struct in an array
Store the days of the week of the event in an array
  this lets us avoid having to keep iterating the checkBoxList

Keep incrementing current date by 1 day


As usual I'm just going to paste the code that makes this up.  I have comments in their
so any questions let me know.

------------------------------------

events.aspx markup

<form id="form1" runat="server">
    <div>
        <asp:Label ID="Label1" runat="server" Text="Event recurrs which days of the week?"></asp:Label>
        <br />
        <asp:CheckBoxList ID="CheckBoxList1" runat="server"
            RepeatDirection="Horizontal" RepeatLayout="Flow">
            <asp:ListItem>Monday</asp:ListItem>
            <asp:ListItem>Tuesday</asp:ListItem>
            <asp:ListItem>Wednesday</asp:ListItem>
            <asp:ListItem>Thursday</asp:ListItem>
            <asp:ListItem>Friday</asp:ListItem>
            <asp:ListItem>Saturday</asp:ListItem>
            <asp:ListItem>Sunday</asp:ListItem>
        </asp:CheckBoxList>
        <br />
        <br />
        <asp:Label ID="Label3" runat="server" Text="Enter Time of Event:"></asp:Label>
        <br />
       
        <!-- make the text boxes into drop down lists for user -->
        <asp:TextBox ID="txtStartTime" runat="server"></asp:TextBox>
        &nbsp;&nbsp;
        <asp:TextBox ID="txtEndTime" runat="server"></asp:TextBox>
        <br />
        <asp:Label ID="Label2" runat="server" Text="Enter date range for recurring event:"></asp:Label>
        <br />
        <asp:TextBox ID="txtStartDate" runat="server"></asp:TextBox>
        &nbsp;&nbsp;
        <asp:TextBox ID="txtEndDate" runat="server"></asp:TextBox>
        <br /><br />
        <asp:Button ID="Button1" runat="server" Text="Enter Event" onclick="Button1_Click" />
</div>
</form>

--------------------------------------

event.aspx.cs

 //store event details
        protected struct CalEvents
        {
            public string eventDate;
            public string startTime;
            public string endTime;
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            DateTime currDate; //used to keep incrementing days
            ArrayList aryDays = new ArrayList(); //store DayOfWeek value
            ArrayList aryEvents = new ArrayList(); //store array of CalEvents structs

            //TODO: properly parse date and time
            //make time text boxes into drop down lists for user to select
            string startTime = txtStartTime.Text;
            string endTime = txtEndTime.Text;
            DateTime startDateRange = DateTime.Parse(txtStartDate.Text);
            DateTime endDateRange = DateTime.Parse(txtEndDate.Text);
            currDate = DateTime.Now.Date;

            //store days of week event should be on
            for (int i = 0; i < CheckBoxList1.Items.Count; i++)
            {
                if (CheckBoxList1.Items[i].Selected)
                {
                    switch(CheckBoxList1.Items[i].Value)
                    {
                        case "Sunday":
                            aryDays.Add(DayOfWeek.Sunday);
                            break;
                        case "Monday":
                            aryDays.Add(DayOfWeek.Monday);
                            break;
                        case "Tuesday":
                            aryDays.Add(DayOfWeek.Tuesday);
                            break;
                        case "Wednesday":
                            aryDays.Add(DayOfWeek.Wednesday);
                            break;
                        case "Thursday":
                            aryDays.Add(DayOfWeek.Thursday);
                            break;
                        case "Friday":
                            aryDays.Add(DayOfWeek.Friday);
                            break;
                        case "Saturday":
                            aryDays.Add(DayOfWeek.Saturday);
                            break;
                        default:
                            break;
                    }
                }
            }

            //TODO: add logic to check and make sure startDateRange is
            //equal or greater than today's date
            //Also check to make sure endDateRange is no more than 12 months out
            while ((currDate >= startDateRange) && (currDate <= endDateRange))
            {
                CalEvents evt = new CalEvents();

                for (int i = 0; i < aryDays.Count; i++)
                {
                    if (currDate.DayOfWeek == (DayOfWeek)aryDays[i])
                    {
                        evt.eventDate = currDate.Date.ToString();
                        evt.startTime = startTime;
                        evt.endTime = endTime;

                        aryEvents.Add(evt);
                    }
                }

                currDate = currDate.AddDays(1.0);
            }


            for (int i = 0; i < aryEvents.Count; i++)
            {
                CalEvents evt = new CalEvents();
                evt = (CalEvents)aryEvents[i];

                //TODO: add logic to write event to database

                //debugging purpose only
                Response.Write(string.Format("Event Info: {0} <br />", evt.eventDate));
            }

        }


Of course I am missing code for all of the user input validation, but you can add that as you choose.  Happy coding.


Be the first to rate this post

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

Tags:
Categories: ASP.NET
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Upload Multiple Files in ASP.NET

November 7, 2008 11:16 by John M

I have seen a lot of different ways to upload multiple files in ASP.NET but they all consisted of either using a lot of javascript, a pre-determined amount of FileUpload controls on the page, or 3rd part controls that will do it for you. I decided to take a different approach and use bytes to utilize multiple files. 

Now this demonstration is actually showing how to upload multiple photos in ASP.NET, but it can very well be used to upload multiple files as well.

The concept is as follows:

One FileUpload control on the page
One DataList to show which images the user will be uploading
Store image information in a dataset with one of the columns being the image in bytes
User has option to remove image from the upload list if they want before uploading it.

I will simply copy and paste the code for what I have done.  I will mention I have not tested this fully in production.  My development Environment is VS 2008, debugging using built in web server in Visual Studio.

This code is for a file called getImage.aspx.  This returns the image in binary for previewing of which images will be uploaded.  You’ll see the main pages uses this page as the ImageUrl in the DataList. I am only pasting the code behind because there isn’t any markup involved.

getImage.aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
 //TODO: error checking for query string

 if(Session["dsPhotoFiles"] != null)
 {
      DataSet tmpDs = new DataSet();
      tmpDs = (DataSet)Session["dsPhotoFiles"];

      for (int i = 0; i < tmpDs.Tables[0].Rows.Count; i++)
      {
         if (tmpDs.Tables[0].Rows[i]["id"].ToString() == Request.QueryString["id"])
         {
             Response.BinaryWrite((byte[])(tmpDs.Tables[0].Rows[i]["fileBytes"]));
             break;
         }
      }
 }
}

 

Below is now the code for the main page used to upload multiple images.

Default.aspx

This is the code inside the form tag

<div>
     <asp:Label ID="Label1" runat="server" Text="Locate File:" />&nbsp;&nbsp;
     <asp:FileUpload ID="fileUp" runat="server" /> &nbsp;&nbsp;
     <br />
     <asp:Label ID="Description" runat="server" Text="Description:"></asp:Label>&nbsp;&nbsp;
     <asp:TextBox ID="txtDesc" runat="server" Width="349px"></asp:TextBox>
     <asp:Button ID="btnAddFile" runat="server" Text="Add File To Upload List"
                onclick="btnAddFile_Click" />
</div>
 
<div>
     <asp:Label ID="lblCurrentFileCount" runat="server"></asp:Label>
     <br />
     <asp:DataList ID="dlPhotoFiles" runat="server" RepeatColumns="10" RepeatDirection="Horizontal">
         <ItemTemplate>
             <asp:Image ID="Image1" runat="server" ImageUrl='<%# string.Format("~/getImage.aspx?id={0}", Eval("id")) %>'
                   Width="50" AlternateText='<%# Eval("fileDesc") %>' />
             <br />
             <asp:LinkButton ID="lnkBtnRemovePhoto" runat="server"
                        CommandArgument='<%# Eval("id") %>' OnCommand="lnkBtnRemovePhoto_Command">Remove</asp:LinkButton>
         </ItemTemplate>                  
      </asp:DataList>
      <br />
</div>
<br />
<div>
     <asp:Button ID="btnUploadFiles" runat="server" Text="Upload File(s)"
                   onclick="btnUploadFiles_Click" />
</div>


Default.aspx.cs

This is all of the code behind:

DataSet dsPhotosFiles = new DataSet();

        protected void Page_Init(object sender, EventArgs e)
        {

            if (Session["dsPhotoFiles"] == null)
            {
                this.initPhotoDS();
                Session.Add("dsPhotoFiles", dsPhotosFiles);
            }
            else
            {
                dsPhotosFiles = (DataSet)Session["dsPhotoFiles"];
            }
        }

        protected void btnAddFile_Click(object sender, EventArgs e)
        {

            if (fileUp.PostedFile.ContentLength > 0)
            {
                //TODO: logic for file extension check
                DataRow dr = dsPhotosFiles.Tables[0].NewRow();

                string fileExt = System.IO.Path.GetExtension(fileUp.PostedFile.FileName);

                byte[] imageBytes = new byte[fileUp.PostedFile.InputStream.Length];
                fileUp.PostedFile.InputStream.Read(imageBytes, 0, imageBytes.Length);

                dr["fileBytes"] = imageBytes;
                dr["filePath"] = fileUp.PostedFile.FileName;
                dr["fileDesc"] = txtDesc.Text;
                dr["id"] = System.Guid.NewGuid().ToString();

                dsPhotosFiles.Tables[0].Rows.Add(dr);
            }

            this.bindDataList();          

            txtDesc.Text = "";
            lblCurrentFileCount.Text = "Current Files To Upload: " + dsPhotosFiles.Tables[0].Rows.Count;
        }

        protected void btnUploadFiles_Click(object sender, EventArgs e)
        {

            try
            {
                for (int i = 0; i < dsPhotosFiles.Tables[0].Rows.Count; i++)
                {
                    //TODO:logic to save image path and description to database
                   
                    string fileName = System.IO.Path.GetFileName(dsPhotosFiles.Tables[0].Rows[i]["filePath"].ToString());

                    byte[] imageBytes;
                    imageBytes = (byte[])dsPhotosFiles.Tables[0].Rows[i]["fileBytes"];

                    //their is no uploading..just writing out the bytes to the directory on the web server.
                    System.IO.File.WriteAllBytes(Server.MapPath(string.Format("~/documents/{0}", fileName)), imageBytes);
                }

                //TODO: show success message logic

                //clear out rows of dataset not the whole dataset
                dsPhotosFiles.Tables[0].Rows.Clear();
                this.bindDataList();
                lblCurrentFileCount.Text = "Current Files To Upload: " + "0";
               
            }
            catch (Exception ex)
            {
                //TODO: show error message of which file did not get uploaded
                throw new Exception(ex.Message);
            }
          
        }

        private void initPhotoDS()
        {
            dsPhotosFiles.Tables.Add("Photos");
            dsPhotosFiles.Tables[0].Columns.Add("fileBytes", Type.GetType("System.Byte[]"));
            dsPhotosFiles.Tables[0].Columns.Add("filePath");
            dsPhotosFiles.Tables[0].Columns.Add("fileDesc");
            dsPhotosFiles.Tables[0].Columns.Add("id");
        }

        private void bindDataList()
        {
            dlPhotoFiles.DataSource = dsPhotosFiles;
            dlPhotoFiles.DataKeyField = "id";
            dlPhotoFiles.DataBind();
        }

        protected void lnkBtnRemovePhoto_Command(object sender, CommandEventArgs e)
        {

            foreach(DataRow dr in dsPhotosFiles.Tables[0].Rows)
            {
                if (dr["id"].ToString() == e.CommandArgument.ToString())
                {
                    dsPhotosFiles.Tables[0].Rows.Remove(dr);
                    break;
                }

            }

            this.bindDataList();
            lblCurrentFileCount.Text = "Current Files To Upload: " + dsPhotosFiles.Tables[0].Rows.Count;
        }

 

Again, I have not tested this fully in product, but it seems to be working very solid right now in my debug environment. 

The one downfall I see to this is that for large photos that could be a lot to store in memory/session.  Now a good thing about this is that it would be very easy to limit the photo/image count a user can upload because you can just check the row count in the dataset and either add it or not to the dataset.

I see a couple of advantages to this:

The image is in memory so their really isn’t any uploading involved because once it’s in memory it’s write it directly to the directy on the web server.
Gives the user the ability to see the photos they are uploading
Gives the user the ability to remove photos before they commit to uploading them
Can write image information to a database if you would like.

As always, I hope this will make it easier for those out their like me who want a decent way to upload multiple files.  Please comment for any bugs found in this.  I will review this over the next couple of days and try in production as well.


Be the first to rate this post

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

Tags:
Categories: ASP.NET
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

ModalPopup nested in GridView

September 24, 2008 18:47 by John M


This may be old news for some of you out there but for those of you who are just starting to use the AjaxControlToolkit I wanted to show how you can nest the ModalPopup inside a GridView.  This technique has worked for the most part.  However, I will caution if you show a lot of records within the gridview  it could slow up performance on rendering the page.  Keep in mind this technique below is adding the ModalPopup to each row within the gridview. 

First you need the following style within the page your CSS sheet

.modalBackground
{
    background-color:#f5f5f5;
    filter:alpha(opacity=80);
    opacity:0.7;
}


Second you will notice we have the AjaxControlToolkit registered on the aspx page, along with a ScriptManager

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>

<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>

Third, you will see the GridView with one TemplateField that has a LinkButton, Panel, Button and the ModalPopupExtender.

The LinkButton is set as the TargetControlID
The Panel is set as the PopupControlID
The Button is set as the OkControlID

<asp:GridView ID="gvSchedule" runat="server" AutoGenerateColumns="false" ShowHeader="false" GridLines="None" HorizontalAlign="Center">
        <Columns>
            <asp:TemplateField>
                <ItemTemplate>
                    <table cellpadding="5" cellspacing="0">
                        <tr>
                            <td>
                                <asp:LinkButton ID="lnkBtnViewDetails" runat="server" Text="View" />
                                <asp:Panel runat="server" ID="pnlDetails" style="display: none; width: 500px; border: solid 1px black; overflow: scroll; height: 400px; background-color: White;">
                                     <asp:Literal ID="Literal1" runat="server" Text='<%# (string)Eval("strDetails") %>'></asp:Literal>                                           
                                </asp:Panel>
                                <ajaxToolkit:ModalPopupExtender ID="modalPopUp1" runat="server"
                                    TargetControlID="lnkBtnViewDetails"
                                    PopupControlID="pnlDetails"
                                    BackgroundCssClass="modalBackground"
                                    DropShadow="false"
                                    OkControlID="btnCloseDetails" />
                            </td>
                        </tr>
   <tr>
                            <td style="text-align: center;">
                                 <asp:Button ID="btnCloseDetails" runat="server" Text="Close Details" />
                            </td>
                        </tr>
                    </table>
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
        <AlternatingRowStyle CssClass="gridAltRowStyle" />
 </asp:GridView>

This is pretty much all you need to utilize the ModalPopup nested within a GridView. 

Note: I handled the GridView binding in the code behind, or you can handle it with a SqlDataSource.

Hope this has helped on how you can utilize the ModalPopup inside a gridview.

 


Be the first to rate this post

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

Stream DVD to XBox 360 via Media Center Extender

September 16, 2008 19:53 by John M

Ok so obviously I always will write something regarding some code or coding concept. However, I'm writing this more on a personal level as to what I was doing, and too be honest I love software and I think that I am able to do this is pretty cool.  And big props to those out there who do design the software that makes this possible.

So this may be old news, but my DVD player recently took a shot and is no longer working, so this is why I got interested in this concept in the first place.  Here is my setup that I currently have

Home Theater system with my Xbox 360 in my living room, and my Windows Vista Ultimate PC in my office.  The Vista box is running a 2.13GHz Core 2 Duo with 2GB of RAM. Yes I know I need to get more RAM, because I also run Virtual PC on here for development purposes.

So since Vista runs Media Center I wanted a way to utilize my Xbox 360 and Media Center to watch my DVD's.  I know I can just pop in a DVD into the 360 but that is besides the point as I'm trying to get rid of having to store all of my DVD's in shelving units. 

Here is what I'm doing to watch my movies via streaming from Media Center to the Xbox 360.

Overall concept is the following:

1. Shrink the DVD to about 4.37 GB
2. Convert the VOB files to AVI files
3. Convert AVI files to WMV files

Seems like a alot of converting but I promise the quality is fine to watch the movies on the 360.

Software Required:

1. DVD Shrink - download it via the link below

http://www.dvdshrink.org/where_en.php

2. DVDx - I actually found this via a Wiki article here

http://www.wikihow.com/Rip-a-DVD-to-an-AVI-or-MPG-File-Using-DVDx


Note: When you download DVDx it will install an XviD MPEG4 Codec and AVISynth Codec as well (you need them both)

3. Windows Movie Maker (built in with Vista Ultimate)

Now I'm not going to go into tons of detail on how to use the software, just what I have done.

- Run DVD shrink and backup your DVD to your Hard Drive to a location your specify. This process takes anywhere from 7-20 minutes

Once this is complete you will have 2 directories, and AUDIO_TS and VIDEO_TS. You can Ignore the audio one

- Now open up DVDx and follow the steps above in the Wiki Article. The only thing I changed from the article is loading up from a File and changing the resolution to 720 x 480

This process takes anywhere from 1.5-2.0 hours.  The end result will either be one AVI or two AVI's.

Next and final step is to convert those AVI's into WMV's so they can play through the XBox 360 Extender.

- Open up Windows Movie Maker and import the AVI's created from the step above.  Drag the two AVI's onto the storyboard and Publish to the computer.

When you publish select "Windows Media DVD Quality"

The end result of this will be the WMV file that allows you to watch the movie via the 360.

So far I have done about 7 movies and the file size averages about 1.6GB per movie.

NOTE: Keep in mind the WMV file is strictly the movie and nothing else (i.e., menu, extras).


VIEWING MOVIES VIA THE XBOX 360

Go ahead and start your XBox and fire up Media Center at this point.

Browse to your WMV file via Media Center and select the movie you want.

Now depending on what TV you may or may not be satisfied with the view.  I personally have a 42" Plasma TV so I have the black bars on the side of the movie.  To eliminate this, I set my Zoom Setting on my 360 to Zoom 3.

And that is that to make your DVD into a WMV so you can stream it to your Xbox 360!  Like I said I have done this with about 7 movies so far and haven't had any problems.

Oh yea keep in mind I'm not a hard core media/video guy...I usually rather spend my time coding or hanging out. But considering my circumstances with my DVD player failing I decided to do this and it works excellent!  Enjoy

I promise I won't write too many of these types of articles, but I couldn't find any useful ones that didn't require configure my box, xbox or media center all wacked out.


Be the first to rate this post

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

Tags:
Categories: General | Software
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

User Authentication in ASP.NET to Prevent Brute Force Attacks

August 22, 2008 16:29 by John M

This article will provide a very simple way to prevent brute force attacks in ASP.NET for whatever authentication method you so choose.  Brute force attacks are when a program will keep feeding usernames and passwords into your login page and hopefully get the right one after thousands and thousands of tries.  I will show you a way to hopefully prevent this, or at least slow it down so it persuades the attacker to hopefully leave your site and move on to the next one. 

First off please always remember to throw a generic message when the username or password is incorrect.  For example a generic error message would be “Incorrect username or password”.  Please do not say “incorrect username” if the password is right and the username is wrong.  Vice versa for the password being correct. This way the attacker doesn’t know what is right or wrong. 

So the method I follow for avoiding this is to sleep the thread on the page if the username or password is incorrect.  I actually sleep the thread anywhere from 2 to 20 seconds.  This means that if the credentials are incorrect it will not respond for 2 to 20 seconds.  It may not seems like a lot, but when a program is trying to feed credentials into the login page…it will have to wait that long to try another one.  This will drastically increase the time the program doing the brute force has to go through. In addition, making the seconds random will also help a bit too.

Now my example is the following scenario.

1.       A CAPTCHA on the web page

2.       Simple username and password text box with customer membership provider

Below is some sample code that is used to check the username and password and also to sleep the thread if it either one is incorrect. This code does not include the code to check the CAPTCHA

aryCreds just actually stores the username and role...that's about it.

protected void lnkBtnLogin_Click(object sender, EventArgs e)
{       
  
ArrayList aryCreds = new ArrayList();        
  
if (users.checkUserAuth(txtUserName.Text, txtPassword.Text))
       
  
{
            
     
aryCreds = users.getUserCreds(txtUserName.Text);           
     
Session.Add("aryCreds", aryCreds);
            
     
Response.Redirect("menu.aspx");
       
  
}        
  
else
       
  
{
           
     
this.delayRequest();
           
     
txtUserName.Text = null;
           
     
txtPassword.Text = null;
            
     
string error = common.ErrorMessage("Incorrect Username or Password");
            
     
this.Page.Controls.Add(new LiteralControl(error));     
        
  
}
 
} 

private void delayRequest()
{       
  
int minSeconds, maxSeconds;
       
  
minSeconds = 2;
       
  
maxSeconds = 20;
       
  
Random rand = new Random();
       
  
System.Threading.Thread.Sleep(rand.Next(minSeconds, maxSeconds) * 1000);

}

 

Notice the delayRequest method. This is getting called if the checkUserAuth method does not return true.  

Also you'll notice the  

Random rand = new Random();
System.Threading.Thread.Sleep(rand.Next(minSeconds, maxSeconds) * 1000);

This is what actually makes the page delay the error message.

Well I hope this has helped some people out there on a way that can help make their page a bit more protected against attackers for a login scenario.


Be the first to rate this post

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


Categories: ASP.NET
Actions: E-mail | Permalink | Comments (3) | Comment RSSRSS comment feed