Web Design, Programming, Tutorials
Archive for January, 2010
Selecting the last item of a collection using Linq-to-sql
Jan 29th
Today I had some problems with Linq-To-SQL. I needed to get the last item from a collection and only return items where the date was older than two weeks from now.
Data Tables
The main items that I want to return from Linq are Revision records. A Revision has a collection of Document_History records that keep track of updates to the revision. The Document_History record has a Date field that is the date and time when the history entry was inserted, or when the revision was modified.
The Problem
When using the data objects that Linq generates, you are allowed to perform some functions, such as Last and Reverse on the collection of items.
Revision.Document_History.Last.Date
The above code would return the most recent date, or the last time a revision was updated.
But, when you try to use the Last method within a Linq statement, Visual Studio throws an error.
The Fix
To get around this error, I figured out that you can select the latest date using a sub query and the Max method. Below is an example of the Linq-To-SQL code that worked for me.
Dim revs As List(Of Revision) = From r In dbcontext.Revisions _
Where (From h In r.Document_History _
Select h.Date).Max <= cutoffDate _
Select r
Configuring IIS 6 and ASP.NET MVC
Jan 28th
By default, IIS 6 does not work with ASP.NET MVC and needs to be configured to use wild-card mapping to get MVC’s routing and clean URLs to work correctly. Unfortunately, IIS 6 does take a performance hit because all requests are processed by ASP.NET. Static files, such as images, CSS, and JavaScript are processed as a dynamic page instead of a static one.
Install ASP.NET MVC
Follow the first two steps of the instructions for installing ASP.NET MVC. The third step can be ignored since Visual Studio will not be installed on the server.
Configuring ASP.NET 2.0
First thing to do is open the IIS Manager ->expand your server ->Web Service Extensions folder. Right-click on the white space under the list of Web Service Extensions and select to Add a new Web service extension…
The New Web Service Extension window will pop open. Enter “ASP.NET v2.0.50727″ as the Extension Name and click the Add button. Browse to the C:\Windows\Microsoft.Net\Framework\v2.0.50727 folder and select the aspnet_isapi.dll file. Make sure to check the “Set extension status is Allowed” button before clicking OK.
This will allow your programs to run ASP.NET 2.0, 3.0, and 3.5 versions of the .NET framework.
Configuring Your Web Application
The next thing to do is open the properties of the Web Site where your web application is. Select the ASP.NET tab and select 2.0.50717 in the ASP.NET version drop down box.
Next, click on the Home Directory tab. Click on the Configuration button. Under the Wild-card application maps area, click the Insert button. Browse to the C:\Windows\Microsoft.Net\Framework\v2.0.50727 folder and select the aspnet_isapi.dll file. Uncheck the “Verify that file exists” before clicking OK. Save your changes and your site should now be able to run ASP.NET MVC and use the routes setup by your application.
Dependency Injection
Jan 27th
Dependency Injection is a design pattern that is used in Object Oriented Programming to create a relationship between two objects without object A depending on object B. Instead, through the use of an Interface, a place-holder for object B can be referenced in object A. Then, object B can be passed into object A where it is utilized. If there is an object C that uses the same interface as object B, it may also be passed into object A.
A Tightly Coupled Relationship
Below is an example of two classes that are tightly coupled, meaning that if we want to replace object B with another class, we must change the code of object A. Object A is dependent on object B to execute.
Public Class ObjectA
Private _obj As ObjectB
Public Sub New(ByVal obj As ObjectB)
_obj = obj
End Sub
Public Sub RunB()
_obj.Run()
End Sub
End Class
Public Class ObjectB
Public Sub Run()
Console.WriteLine("Run from objectB")
End Sub
End Class
A Loosely Coupled Relationship
Now, let’s look at a better approach that will allow us to replace ObjectB with another class using the same interface or replace it with a child class of ObjectB.
Below, the ObjectB class now implements the IObjectB interface and the references to ObjectB in ObjectA have been replaced with a reference to the interface IObjectB instead.
Public Interface IObjectB Sub Run() End Interface
Public Class ObjectA
Private _obj As IObjectB
Public Sub New(ByVal obj As IObjectB)
_obj = obj
End Sub
Public Sub RunB()
_obj.Run()
End Sub
End Class
Public Class ObjectB
Implements IObjectB
Public Sub Run() Implements IObjectB.Run
Console.WriteLine("Run from objectB")
End Sub
End Class
Now, ObjectA can execute no matter if we pass into it a copy of ObjectB or another class that implements the IObjectB interface. The Interface ensures that all objects that implement it will have a subroutine called Run. That is all that ObjectA needs to know. This breaks ObjectA’s dependency on ObjectB.
The Repository Pattern
Jan 26th
The repository pattern is a design pattern that creates repositories of data that talk to a data source. These repositories are used to segregate the code that talks to a data source from the rest of your program. For example, your code that communicates to a database connection is stored within a repository class. Communication between your program and the database is all funnelled through the repository class.
In Domain Driven Design, you create data objects that are logical representations of the data stored within a data source; such as a database. These data objects may not mimic the design of a database, but instead be a more logical grouping of properties and methods. The repository pattern can be used to create a repository class for each data object, where that object can then be created, read, updated, or deleted (CRUD) from the data source.
Using the repository pattern with Dependency Injection allows for the repository class to be mocked during testing, where a more controlled and faster repository can be created. Also, if the data source changes to a XML file or another database, the repository class can be replaced.
The Repository pattern is one of the design patterns that I use to build a more maintainable and flexible application.
Vector class for Lotus Script
Jan 25th
The following is a script library written in Lotus Script to allow programmers to use a vector in their Lotus Script code.
Option Declare Option Base 0 Public Class Vector 'Private data members Private vArray As Variant Private vCapacity As Integer Private vSize As Integer Public Sub New() 'Initialize variables Call SetCapacity(0) Call SetSize(0) Call Reserve(10) End Sub Public Sub Delete() Call EraseAll() 'Clear the array Set vArray = Nothing End Sub Private Sub SetCapacity(newCapacity As Integer) vCapacity = newCapacity End Sub Public Function Capacity() As Integer Capacity = vCapacity End Function Private Sub SetSize(newSize As Integer) vSize = newSize End Sub Public Function Size() As Integer Size = vSize End Function Public Function Empty() As Boolean 'Declare variables Dim valid As Boolean 'Get the size If (Size() = 0) Then valid = True Else valid = False End If 'Return if the vector is empty Empty = valid End Function Public Sub Reserve(minCapacity As Integer) 'Declare variables Dim openElements As Integer Dim newCapacity As Integer 'Initialize variables openElements = Capacity() - Size() newCapacity = Capacity() 'Check if there are any open slots remaining If (openElements = 0) Then newCapacity = (Capacity() * 1.5) End If 'Make sure that the minimum capacity is stored If (newCapacity < minCapacity) Then newCapacity = minCapacity End If 'Check if a change to the capacity is being made If (Not(Capacity() = newCapacity)) Then 'Check the size to determine if the array's contents need to be 'saved while redimensioning the array If (Size() = 0) Then 'Nothing stored yet, perform redim Redim vArray(newCapacity) Else 'Keep the array's contents while extending its boundaries Redim Preserve array(newCapacity) End If 'Update the capacity Call SetCapacity(newCapacity) End If End Sub Public Sub PushBack(newItem As Variant) 'Check if the passed item/items is actually an array or a list If ((Not(Isarray(newItem))) And (Not(Islist(newItem)))) Then 'Add the single item Call AddItem(newItem) Else 'Add multiple items Forall item In newItem Call AddItem(item) End Forall End If End Sub Private Sub AddItem(newItem As Variant) 'Declare variables Dim newSize As Integer 'Initialize variables newSize = Size() + 1 'Make sure there is enough capacity in the vector Call Reserve(newSize) 'Insert the item into the vector If (Isobject(newItem)) Then Set vArray(Size()) = newItem Else vArray(Size()) = newItem End If 'Increment the vector size Call SetSize(newSize) End Sub Public Function At(index As Integer) As Variant 'Check the vector's index boundaries If ((index < 0) Or (index => Size())) Then Error 2000, _ "[Vector Class]:(Function: At): Index out of bounds." 'Check if the item is an object If (Isobject(vArray(index))) Then Set At = vArray(index) Else At = vArray(index) End If End Function Public Sub Erase(index As Integer) 'Check if the index is out of bounds If ((index < 0) Or (index => Size())) Then Error 2000, _ "[Vector Class]:(Function: Erase): Index out of bounds." 'Declare variables Dim newArray As Variant Dim x As Integer Dim y As Integer 'Initialize variables y = 0 'Make a new array with the same capacity Redim newArray(Capacity()) 'Loop through each element of the vector For x = 0 To Size() - 1 'Check if the current index is the one to remove If ((x <> index) And (Not(y > Size()))) Then 'Check if the item is an object If (Isobject(vArray(x))) Then Set newArray(y) = vArray(x) Else newArray(y) = vArray(x) End If 'Increment the index counter y = y + 1 End If Next x 'Subtract one from the vector size Call SetSize(Size() - 1) 'Set the new array as the vector vArray = newArray End Sub Public Function BeginIndex() As Integer BeginIndex = 0 End Function Public Function EndIndex() As Integer EndIndex = Size() - 1 End Function Public Sub EraseAll() 'Declare variables Dim x As Integer 'Loop through each element of the array For x = BeginIndex() To EndIndex() 'Delete each element of the arra 'Check if the item is an object If (Isobject(vArray(x))) Then Set vArray(x) = Nothing End If Next 'Reset the size. Call SetSize(0) End Sub End Class
Copy the above code and paste into a script library for the database where you would like to use a vector. Then, you can use the example below to use the vector class.
Use "libVector" Dim vector As New Vector() dim obj As String obj = "hello" 'Load any object into the vector. Call vector.PushBack(obj) Call vector.PushBack(obj) 'Loop through the vector to retrieve objects. For i = vector.BeginIndex() To vector.EndIndex() Print "Item: " & i & " " & vector.At(i) Next
Adding social media icons to the Mystique theme
Jan 22nd
If you are using WordPress and the Mystique theme, such as this site, then the following instructions will help you with adding additional social icons above the menu bar.
Creating the images
The number of image files you need to create depends on the number of icons you wish to have. You can combine three icons per image file and use CSS to pull the desired icon from the file to display.
For example, below are the two image files used by this site. Since I only have six icons, I can make them all fit into two files. This is important because the browser only has to download two images to display these six icons. Each HTTP request back to the server can slow down a website. Using CSS to display the images also helps by allowing the browser to cache the images and reduce text in the HTML file.
These images were created in Photoshop using a transparent background. You can download various free social media icons. Search the internet and find some that you like that are 64 x 64 pixels. To create the tilted look, rotate the icon 30° and then resize so the height is 64 pixels. The total width of the image should be 64 x the number of icons, but remember to only store three per image file.
Changes to the CSS
Inside the Mystique theme, open the style.css file. Around 100 lines down into the file, you will see some code similar this:
#header .nav-extra
{width:64px;height:36px;display:block;position:absolute;bottom:18px;z-index:10;}
#header .nav-extra span
{display:none;}
#header .nav-extra.rss
{background:transparent url(images/nav-icons.png) no-repeat right top;right:20px;}
#header a.twitter
{background:transparent url(images/nav-icons.png) no-repeat left top;right:85px;}
Just below this block of CSS is where we will add our additions, which will be very similar to the last line of CSS implementing the twitter class on the “a” tag.
Add the following CSS to use the same image files and icons that I have used. You can change the name following the “a.” to anything you wish, but it should be something descriptive.
#header a.facebook
{background:transparent url(images/nav-icons.png) no-repeat center top;right:147px;}
#header a.myspace
{background:transparent url(images/nav-icons2.png) no-repeat right top;right:209px;}
#header a.flickr
{background:transparent url(images/nav-icons2.png) no-repeat center top;right:273px;}
#header a.linkedin
{background:transparent url(images/nav-icons2.png) no-repeat left top;right:338px;}
Here I have added additional icons for Facebook, MySpace, Flickr, and LinkedIn.
To reference the correct icon, using the background: CSS property, you can call the image file (nav-icons.png and nav-icons2.png). Using the top right, left and center keywords, you can select the icon file to use from the image. In the above example, the nav-icons.png file has three icons…by selecting the center one, I’m pulling out the Facebook icon from the first image above.
The “right” property positions the icon however many pixels from the right side of the screen. You can adjust this number to increase or reduce the amount of space between the icons.
Changes to the header
The last thing we need to do is add the HTML code to the header template. This will tell your browser to display the icons. Open the header.php file within the mystique theme, then look for the following block of code around line 55.
if ($twituser): ?>
<a href="http://www.twitter.com/<?php echo $twituser; ?>" class="nav-extra twitter"
title="<?php _e("Follow me on Twitter!","mystique"); ?>">
<span><?php _e("Follow me on Twitter!","mystique"); ?></span>
</a>
<?php endif; ?>
Next, we’ll add in our new icon HTML below the HTML shown above.
<a href="http://www.facebook.com/YOURPROFILE" class="nav-extra facebook"
title="<?php _e("My Facebook Profile.", "mystique"); ?>">
<span><?php _e("My Facebook Profile.", "mystique"); ?></span>
</a>
<a href="http://www.myspace.com/YOURPROFILE" class="nav-extra myspace"
title="<?php _e("My MySpace Profile.", "mystique"); ?>">
<span><?php _e("My MySpace Profile.", "mystique"); ?></span>
</a>
<a href="http://www.flickr.com/photos/YOURPROFILE/" class="nav-extra flickr"
title="<?php _e("My Flickr Photos.", "mystique"); ?>">
<span><?php _e("My Flickr Photos.", "mystique"); ?></span>
</a>
<a href="http://www.linkedin.com/in/YOURPROFILE" class="nav-extra linkedin"
title="<?php _e("My LinkedIn Profile.", "mystique"); ?>">
<span><?php _e("My LinkedIn Profile.", "mystique"); ?></span>
</a>
Make sure that you replace YOURPROFILE with the correct link information to your profile for these social media sites.
One thing that is important to notice is the CLASS attribute. There are two classes added to each “a” tag: nav-extra and the name of whatever social media icon you are displaying. This name must match the name specified in the CSS above that follows the “a.”.
The PS3 Media Server
Jan 21st
If you have a Playstation 3, or even an Xbox 360, you should take a look at the PS3 Media Server. I have tried using Windows Media Center to serve video content, and while it does work, the video formats seem very limited. The PS3 Media Server seems to support just about any type of video that I would want to use; such as MPG, MP4, MKV, M2TS, and VOB.
I was most impressed by how backing up a movie DVD at 100% quality (around 7 GB), I was still able to stream to my PS3 and the video quality looked as if the DVD were playing in the PS3. In testing, I was able to play Blu-Ray video as well, although the video did jump around a bit on some clips; it could have been a bad backup. Both my computer and the PS3 were wired on a 1GB network.
There are some problems:
- Seeking does not work the best, specifically from the Xbox 360.
- DVDs are typically split into roughly 1GB VOB files. If there are many of these, it may be difficult to find the desired VOB that contains the movie. Usually, the movie is the largest one. You can use the command below to combine the VOBs into one file…which then can be renamed to something.mpg.
copy /b file1.vob + file2.vob + file3.vob new.vob
So, if you would like to keep your DVD collection in good condition and have the space to store your movies on your computer, give the PS3 Media Server a try. You can backup your DVDs to your computer using a tool like DVDShrink, then play them over your network. No more searching for the disc to watch a movie.
Disclaimer: You should only backup media that you own. Do not illegally copy movies or music.
You can download the PS3 Media Server from google.
Some bad news
Jan 20th
Today I found out that a good friend’s father passed away yesterday. He was a very intelligent and respected man in the town where I grew up and went to school. I had spent many a day hanging out at his house with his son through high school and after. The world is a little darker without the bright shining light that was Ed Crow. He will be missed…
Clearing the Client Version from the Lotus Notes Directory
Jan 20th
With the latest version of Lotus Notes (8.5.1), you can now view the version of your clients by looking in the People -> by Client Version view. One problem with this, however, is that your users will show each client they have logged in as. Over the years, you may accumulate many versions for each user.
During an upgrade, you may wish to see what users are using the previous version of client against the ones who have the new version installed. But first, we’ll need to clean up the directory so we don’t see all this old version history.
To clean up these fields, you need to write an agent that will empty them for each selected person. This will allow you to run the clean up agent on only the users you wish to run it on.
Writing the agent
Open up the pubnames.ntf template file in your Notes Designer. You’ll need to go to Code and double-click on Agents to see the current agents for the template.
We’ll create a new agent and give it a name. Below is the code for the agent. Copy and paste it in the Designer.
Option Public
Option Declare
Sub Initialize()
'Declare.
Dim s As New NotesSession
Dim db As NotesDatabase
Dim dc As NotesDocumentCollection
Dim doc As NotesDocument
'Initialize.
Set db = s.Currentdatabase
Set dc = db.Unprocesseddocuments
Set doc = dc.Getfirstdocument()
While(Not(doc Is Nothing))
If (doc.Form(0) = "Person") Then
Call doc.Removeitem("ClntBld")
Call doc.Removeitem("ClntDate")
Call doc.Removeitem("ClntDgst")
Call doc.Removeitem("ClntMachine")
Call doc.Removeitem("ClntPltfrm")
Call doc.Save(False, False, False)
End If
Set doc = dc.Getnextdocument(doc)
Wend
End Sub
Now, after you refresh your names.nsf file, you can go to the Action menu and find your agent. Running the agent will only process those Person documents that you have selected.
Scheduling A Task In A Web Application On A Windows Server
Jan 19th
When writting web applications, there may be times when you would like to perform some task automatically at the same time or every X number of hours. Web applications only execute their code when a request is made from a client’s browser. Because of this, scheduled tasks within the web application will not work.
There are a few different options:
- Build a separate Windows Service application that can connect to the assemblies your web application uses to execute the scheduled task.
- Build a separate Windows application that communicates with a web service that your web application also uses to perform the scheduled task.
- Use the Windows Scheduler to call the URL of the action to perform the task.
The first option might sound good at first, but creating a separate program that talks to your web application’s library files is a bad idea. Maintenance will become a problem as you change your web application. Since the code is in two places, unit testing will not tell you that the class library you just changed has now broken your scheduled tasks in your windows service.
The second option is slightly better, but you still may have issues with changing your class library.
The third option is the one that I will show you how to configure. We will setup a VBS script that will perform a call to any web address we pass to it. Then, we’ll setup a batch file that calls the VBS script and passes in one or more URLs to execute. And finally, we’ll go through using the Windows Scheduler to create the scheduled task when the batch file should execute.
The primary advantage to this method is that you get to keep all of your code together in your web application. You simply setup an action that performs whatever task you wish to schedule and make sure that action is callable from an anonymous user.
WebRequest.vbs
You may copy the following code and paste into a text file. Then, rename the file to WebRequest.vbs. The script basically takes an argument that is passed into it as the URL. The HTTP object is setup and then the URL is called using a GET request. Then, the returned status is checked to see if the request was successful or not.
url = WScript.Arguments.Item(0)
'WScript.echo url
set WshShell = WScript.CreateObject("WScript.Shell")
set http = CreateObject("Microsoft.XmlHttp")
http.open "GET", url, FALSE
http.send ""
if (http.Status = 200) then
WScript.echo "Request successful."
else
WScript.echo "Error: " & http.Status
end if
set WshShell = nothing
set http = nothing
The Batch File
Calling the WebRequest.vbs file from a batch file is very easy. Simply create a new text file, calling it whatever you’d like, and paste in the following line of text. Rename the file to .BAT when finished.
cscript WebRequest.vbs "http://www.domain.com/controller/action"
Scheduling The Task
From your Windows server, open the Control Panel and then open the Scheduled Tasks item. Next, click on Add Scheduled Task. Choose any application to schedule. This will be changed later on. Configure how often you wish the schedule to run and enter a user name and password to run the schedule as. This users should have access to running the web browser from the server.
After your new scheduled task has been created, open it. In the Run text box, type in the full path to your batch file. Then, in the Start In text box, type in the full path without the batch file name. You can also adjust your scheduled time from within here. Click OK to save the changes and your scheduled task should be ready.
You can test the Windows Scheduler by setting the scheduled time to a minute or two in the future and then waiting for it to execute. If you just wish to test your action, or manually run it, you can simply run the batch file.