August 2005 - Posts - Peter's Software House

August 2005 - Posts

New PC Update

Once again thanks to Matt he gave me some more guidance, decided on an SLI setup instead of the ATI X800XL.  I also completely forgot about a mouse and keyboard on the last post.
Here is the full setup as I've ordered it now.  Should have most of the components by friday, I hope, otherwise early next week.

Qty Description
1 Microsoft Wireless Optical Desktop Elite, PS/2 & USB
1 AMD Athlon 64 x2 Dual Core 3800+ 1Mb Cache Socket 939 2.0GHz CPU
4 512MB PC3200 DDR400 RAM
1 Western Digital 320GB External HDD
2 Western Digital 250G 7200 8M SATA WD2500JD Serial ATA
1 Sony SDMHS95PS 19" Clear Bright LCD Display
1 XION Black w/350W (Case)
1 Sony DRU800A Internal Double-Layer DVD RW Drive
1 Asus A8N-SLI Premium Athlon64 Motherboard
1 Leadtek PX6800GT-TDH-256-SLI nVidia GeForce 6800GT PCIE Video Card, 256Mb DDR, 1x TV Out, 1x DVI
1 Leadtek 2000 Expert PCI TV Tuner, Conexant Chipset, with Remote Control, FM Radio, Capture

I hope the 350W PSU is ok, but I'll monitor that, can always just get a bigger PSU.  Must get another 19” LCD, but the cash is a bit low at the moment, so will have to settle for the 17” CRT I currently use as my second monitor.  Matt, onething I can't find a lot of info on, if I want to install another SLI card, does it have to be exactly the same, of can it be a newer version? [Update: You can mix the SLI cards, but it is not recommended, the motherboard I got actually allows you to mix different SLI cards, but the recommended way is to have identical cards running]

I think this should last me for quite a while though. :D

Posted by Pieter | 1 comment(s)
Filed under:

New PC

For reasons beyond my control I had to get new accomodation and unforetunately the new place does not have a big screen TV / DVD etc setup.  So I decided stuff this, I wanted a new PC for ages now and I'm not going to spend money on a TV as well, so let's buy a bumper PC.

Here is my specs of stuff I ordered:

AMD Athlon 64 x2 Dual Core 3800+ 1Mb Cache Socket 939 2.0GHz CPU
2GB DDR400 RAM
Sony SDMHS95PS 19" Clear Bright LCD Display , I also have a 17" CRT
350W XION case, I hope this is big enough...
Gigabyte GA-K8NXP-9 (nForce4 Ultra, PCI-EX16, SKT939)
2 x Western Digital 250G 7200 8M SATA WD2500JD Serial ATA
Gigabyte GV-RX80L512V ATi Radeon X800XL PCIE Video Card, 512MB DDR, 1x TV Out, 2x DVI, 1x Video In
Sony DRU800A Internal Double-Layer DVD RW Drive

I hope all this works together, I'll keep you posted as I assemble it this week.  This has sofar set me back around NZ$3,500.  I've also ordered a 320GB External drive last week for NZ$450.  I'm going to use my laptop as a Win2003 internet gateway server for the house.  Thanks to Matt for his input a while back, let me know what you think of this setup Matt.

Posted by Pieter | 1 comment(s)
Filed under:

IDisposable Pattern

IDisposable Pattern:

#region IDisposable 
private bool disposed; 
 
private void Dispose(bool disposing) 
{ 
    if (!(this.disposed)) 
    { 
        if (disposing) 
        { 
            if(someDisposableObject != null)
            {
                someDisposableObject.Dispose();
            }
        } 
    } 
    this.disposed = true; 
} 
 
public void Dispose()
{            
    Dispose(true); 
    GC.SuppressFinalize(this); 
}
 
protected void Finalize() 
{ 
    Dispose(false); 
}
#endregion

Posted by Pieter | 2 comment(s)

Event Pattern

I've been using the EventHandlerList object in any of my objects with a lot of events as most events do not get used all of the time and you tend to wire only a couple everytime you use an object.  Anyway this is the Event Pattern I use:

private EventHandlerList events = new EventHandlerList();
 
protected virtual void OnAuthenticate(AuthenticateEventArgs e)
{
    AuthenticateEventHandler eventHandler = this.events["Authenticate"] as AuthenticateEventHandler;
    if (eventHandler != null)
    {
        eventHandler(Application.Instance, e);
    }
}
 
public event AuthenticateEventHandler Authenticate
{
    add
    {
        events.AddHandler("Authenticate", value);
    }
    remove
    {
        events.RemoveHandler("Authenticate", value);
    }
}

Posted by Pieter | with no comments
Filed under:

Microsoft SmartClient Offline Application Block

Seems I was a bit to kind to the Offline AB.  The quickstart is not very complete and does not show you all that much. I had to go and dig a lot deeper myself to try and figure out what really was going on.  I would recomment that they create Quickstarts that actually work correctly, saving people who look at the ABs a lot of time.  On the other hand when has development ever been easy? :D The Managing Offline Clients with the Smart Client Offline Application Block is sofar the best in showing how to use the most obvious features. 

How to access the cached data?

Use the ReferenceDataCache of the OfflineBlockBuilder Instance.  It returns the cached data with the key you specified in your ServiceAgent method.  If you have set an expiration time the Offline AB will refresh the cache after the expiration period.  Pretty neat.

Posted by Pieter | 2 comment(s)
Filed under:

Managing Offline Clients with the Smart Client Offline Application Block

Managing Offline Clients with the Smart Client Offline Application Block

Very good example of using the Offline Application Block, dare I say it is better then the Microsoft samples? Yes I do actually!

Posted by Pieter | with no comments
Filed under:

IsolatedStorageFileStream

Praise the lord....

I have seen the light and it is IsolatedStorageFileStream.

No don't ask me why I've only noticed it now, been playing with the Offline application block, which by the way is the only AB I got working the first time round, and found IsolatedStorage, way cooool. :D

Clearly I do way to much server side work and way to little client side.  That is changing with the SmartClient application I am writing.  Got the Authentication sorted this weekend and last week got the whole Add-In architecture humming along.  The Authentication was tricky as I needed to cater for users within the domain, as well as users outside (agents and resellers) the domain to be able to authenticate and securely store the authentication and authorization bits and allow for offline access to the system without losing the security integrity of the system, as there is going to be very sensitive sales data on it and so the security needs to be pretty robust.

Any hooo, I see plenty of posts coming from this project. 

Posted by Pieter | with no comments
Filed under:

Encryption

I needed to encrypt some string and I found this code, but it had a few bugs, so here is it fixedup. :D

http://aspalliance.com/cookbook/ViewSource.aspx?Filename=Recipe1509vb.aspx&RecipeType=ASPX

    public sealed class Encryption
    {
        private Encryption()
        {
        }
 
        public static byte[] EncryptData(byte[] ClearText, string password)
        {
            int keySize = 24;
            byte[] hash;
            byte[] passwordArray = new byte[password.Length];
            byte[] tdeskey = new byte[keySize];
            byte[] IV = {1, 2, 3, 4, 5, 6, 7, 8};
            UTF8Encoding encoder = new UTF8Encoding();
            encoder.GetBytes(password, 0, password.Length, passwordArray, 0);
            SHA1CryptoServiceProvider SHA = new SHA1CryptoServiceProvider();
            hash = SHA.ComputeHash(passwordArray);
            for (int i = 0; i < keySize; i++)
            {
                tdeskey[i] = hash[i % hash.Length];
            }
            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            ICryptoTransform cryptoTransform = tdes.CreateEncryptor(tdeskey, IV);
            MemoryStream EncryptedStream = new MemoryStream();
            CryptoStream crStream = new CryptoStream(EncryptedStream, cryptoTransform, CryptoStreamMode.Write);
            crStream.Write(ClearText, 0, ClearText.Length);
            crStream.FlushFinalBlock();
            EncryptedStream.Position = 0;
            byte[] output = new byte[EncryptedStream.Length];
            EncryptedStream.Read(output, 0, Convert.ToInt32(EncryptedStream.Length));
            crStream.Close();
            EncryptedStream.Close();
            return output;
        }
 
        public static byte[] DecryptData(byte[] CypherText, string password)
        {
            int keySize = 24;
            byte[] hash;
            byte[] passwordArray = new byte[password.Length];
            byte[] tdeskey = new byte[keySize];
            byte[] IV = {1, 2, 3, 4, 5, 6, 7, 8};
            UTF8Encoding encoder = new UTF8Encoding();
            encoder.GetBytes(password, 0, password.Length, passwordArray, 0);
            SHA1CryptoServiceProvider SHA = new SHA1CryptoServiceProvider();
            hash = SHA.ComputeHash(passwordArray);
            for (int i = 0; i < keySize; i++)
            {
                tdeskey[i] = hash[i%hash.Length];
            }
            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            ICryptoTransform cryptoTransform = tdes.CreateDecryptor(tdeskey, IV);
            MemoryStream DecryptedStream = new MemoryStream();
            CryptoStream crStream = new CryptoStream(DecryptedStream, cryptoTransform, CryptoStreamMode.Write);
            crStream.Write(CypherText, 0, CypherText.Length);
            crStream.FlushFinalBlock();
            DecryptedStream.Position = 0;
            byte[] output = new byte[DecryptedStream.Length];
            DecryptedStream.Read(output, 0, Convert.ToInt32(DecryptedStream.Length));
            crStream.Close();
            DecryptedStream.Close();
            return output;
        }
    }

 

 

Posted by Pieter | 2 comment(s)
Filed under:

Creating a Smart Client Application

As you know I've been investigating the development of a Smart Client application.

Well it seems that we are going to go forward with the development and I have made some decisions on what technologies we are going to use with the development of this application.

  1. We are going to support the .NET 1.1 framework for now.   The risks involved in using the .NET 2.0 beta is just to great for us for now although we are going to design and develop with 2.0 in mind to ensure that when we upgrade that it will be a relatively painless experience.
  2. As our Data Access framework we are going to use Codus.  Codus stood out for me as it generates a webservices layer and some other features that I liked was the generation of NUnit tests, all the generated code contains documentation tags, etc...  Some of you may know that I am a huge NEO fan, unfortunately for NEO, it doesn't really support the offline architecture that we are going to implement here at the moment, which is a pity, but at least there are other applications out there that do, so for now that is what I'll be using.
  3. We will also be making use of Sean McCormack's Adapdev.Net, mostly because it is a much less complex implemention of features found in the Microsoft Enterprise Library that we want to use.
  4. We will be using the Offline Application Block from Microsoft to manage the offline capabilities of our application.
  5. For our plugin architecture we will be using the Razor::Winforms Framework.  I also like Razor AutoUpdate features and Configuration options.
  6. We are also sticking with CVSNT and TortoiseCVS.
  7. NUnit for Unit Testing.

So as you can see we have taken what we needed to develop this application from several sources.  I will keep you posted on the progress of this little project.  I want to talk about our hurdles, mistakes, solutions and general progress.  I hope that this will then also be the documentation for the developer that has to take over from me when I leave here next year.

Posted by Pieter | 2 comment(s)
Filed under:

Smart Client Resources

In my search for Smart Client samples and articles I have found a few gems:

These were all done by Omar Al Zabir, his website is also very impressive.  The only problem I had was closing some of the pages on his website, just use Alt-F4 to close them if you are at a lost as to what to do.

Posted by Pieter | with no comments
Filed under:

Smart Client

I'm busy doing a proof of concept for a smart client application.  I am trying to look at the www.learn247.net site for some code and best practices, but I cannot seem to get onto the site, has anybody else had any issues?  Or are there any other sites that can give me good examples of smart client apllication architecture?

[Update: getting onto the site now, but it is sooooooo sloooooow!]

Posted by Pieter | 2 comment(s)
Filed under:

GhostDoc 1.3.0 Beta 1 Released

This is one of my essential tools and Roland WeigeIt has released beta 1.

Go and have a look here.

Posted by Pieter | 1 comment(s)
Filed under: ,

Bokke BO!!!!!

Yea bokke!!!!

I'm just happy these bloody kiwi commentators got a bloody nose! :D

Posted by Pieter | with no comments
Filed under:

Now we want to edit user data...

In a previous post I explained how you can the user display page (UserDisp.aspx) in WSS.  Well like typical users they came back and said “Man this is cool, but it would be even better if we could now edit this information here”, instead of where it is suppose to be edited which is a whole seperate application.  But being the little steam engine that can I said no sweat guys.

It was actually very easy, just a few gotchas I need to tell you about, the process is very similar to what I explained in the other post.

What I forgot to mention in the previous post was that I ended up doing all the work to get the display info in the OnLoad method.  Here is the code from UserDisp.cs:

using System;
using System.Web.UI.WebControls;
using PSH.DataAccess.Model;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
 
namespace PSH.SharePoint.ApplicationPages
{
    /// 
    /// Summary description for UserDisp.
    /// 
    public class UserDisp : Microsoft.SharePoint.ApplicationPages.UserDisp
    {
        protected Label lblJobTitle;
        protected Label lblPhone;
        protected Label lblFax;
        protected Label lblMobile;
 
        protected int UserID
        {
            get
            {
                if (Request.QueryString["ID"] == null)
                {
                    return -1;
                }
                return int.Parse(Request.QueryString["ID"]);
            }
        }
 
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
 
            try
            {
                    SPWeb site = SPControl.GetContextWeb(Context);
                    site.AllowUnsafeUpdates = true;
 
                    SPUser spUser = site.AllUsers.GetByID(this.UserID);
 
                    UserFactory userFactory = new UserFactory(DataAccess.Common.Context.ObjectContext());
                    //Could have use FindUnique, but if NEO finds no entry it throws an Exception and I didn't want that to happen. 
                    UserList userList = userFactory.Find("NetworkName = {0}",  spUser.LoginName.ToLower() );
                    if (userList.Count == 1)
                    {
                        User user = userList[0];
                        lblJobTitle.Text = user.JobTitle;
                        lblPhone.Text = user.Phone;
                        lblFax.Text = user.Fax;
                        lblMobile.Text = user.Mobile;
                    }
            }
            catch ()
            {}
 
        }
 
    }
}

I use NEO for my DAL and you should just replace that with your code, sorry, but I don't have the time to go and write something generic right now.  At least it give you an idea of what I did.

Ok so that was very easy, now to edit the data.  So I opened UserEdit.aspx.  Once again you need to change the Inherits section to look at your Assembly:

<%@ Page Language="C#" Inherits="Formway.SharePoint.ApplicationPages.UserEdit"     ValidateRequest="False" %> 

Then I searched for “Display Name” and found txtName is the textbox control for the users name.  I copied the label and textbox and created a few for my data:

<tr>
    <td class= "ms-vh"><label for="txtTitle"> Title:label>td>
    <td class= "ms-propertysheet"><asp:TextBox Tabindex=5 id=txtTitle MaxLength=255 runat=server title="Title"  CssClass="ms-long" />td>
tr>
<tr>
    <td class= "ms-vh"><label for="txtPhone"> Phone:label>td>
    <td class= "ms-propertysheet"><asp:TextBox Tabindex=5 id=txtPhone MaxLength=255 runat=server title="Phone"  CssClass="ms-long" />td>
tr>
<tr>
    <td class= "ms-vh"><label for="txtFax"> Fax:label>td>
    <td class= "ms-propertysheet"><asp:TextBox Tabindex=5 id=txtFax MaxLength=255 runat=server title="Fax"  CssClass="ms-long" />td>
tr>
<tr>
    <td class= "ms-vh"><label for="txtMobile"> Mobile:label>td>
    <td class= "ms-propertysheet"><asp:TextBox Tabindex=5 id=txtMobile MaxLength=255 runat=server title="Mobile"  CssClass="ms-long" />td>
tr>

As you can see I only used textboxes, as this was all I needed at the moment, but you can do this with dropdownlist, checkboxes etc, whatever you need.

You can then also edit the DoValidateAndSubmit() javascript function if you want to do some client side validation of the data.  I left it as it is as my data for now was not required and didn't need any special attention.  So now that we have finished the aspx page which I hope you have backed up before you started editing... :D  Let's focus now on our implementation of UserEdit.cs.  Here is the code:

using System;
using System.Web.UI.WebControls;
using Formway.DataAccess.Model;
using Microsoft.SharePoint;
using Microsoft.SharePoint.ApplicationPages;
using Microsoft.SharePoint.WebControls;
 
namespace Formway.SharePoint.ApplicationPages
{
    /// 
    /// Summary description for UserEdit.
    /// 
    public class UserEdit : Microsoft.SharePoint.ApplicationPages.UserEdit
    {
        protected TextBox txtTitle;
        protected TextBox txtPhone;
        protected TextBox txtFax;
        protected TextBox txtMobile;
 
        protected int UserID
        {
            get
            {
                if (Request.QueryString["ID"] == null)
                {
                    return -1;
                }
                return int.Parse(Request.QueryString["ID"]);
            }
        }
 
        protected override void OnLoad(EventArgs e)
        {
            CUtil.EnsureAuthentication();
 
            SPWeb site = SPControl.GetContextWeb(Context);
            SPUser spUser = site.AllUsers.GetByID(this.UserID); //site.AllUsers[user.NetworkName];
 
            UserFactory userFactory = new UserFactory(DataAccess.Common.Context.ObjectContext());
            UserList userList = userFactory.Find("NetworkName = {0}", spUser.LoginName.ToLower());
            if (userList.Count == 1)
            {
                User user = userList[0];
 
                if (!this.IsPostBack)
                {
                    this.InitPage();
                    txtTitle.Text = user.JobTitle;
                    txtPhone.Text = user.Phone;
                    txtFax.Text = user.Fax;
                    txtMobile.Text = user.Mobile;
                }
                else
                {
                    spUser.Name = txtName.Text;
                    spUser.Email = txtEmail.Text;
                    spUser.Notes = txtNotes.Text;
                    spUser.Update();
 
                    user.Email = txtEmail.Text;
                    user.JobTitle = txtTitle.Text;
                    user.Phone = txtPhone.Text;
                    user.Fax = txtFax.Text;
                    user.Mobile = txtMobile.Text;
                    user.Save();
 
                    this.UpdateUserInfo();
                }
            }
        }
    }
}

Now I need to point out a few things:

  • As you can see I do not call base.OnLoad(e); in the OnLoad method.  It works fine on the display of the data, but stuffs you up on the postback as the UpdateUserInfo() method will redirect you to another page and it gets called in base.OnLoad.
  • So I call UpdateUserInfo() right after I have updated my details so that the display name, email and notes can be saved to the SPUser object and that the normal redirects can take place.
  • I also call the InitPage() method to ensure that all the normal data is updated during the first display of the page.

Just remember that although this is great, if Microsoft releases a new version of WSS it will most likely override these changes, so keeping track of it somewhere (Source Control?) is essential, also documenting it is important for the poor idiot that comes after you and loses functionality when he upgrades the system. :D

I've blogged about it so who ever has to take over from me had better learn to read my blog! ;-)

[Just another important point, the profile editor on SPS is rather impossible to change, you can see just by looking at the code and different implementations in the code that there was no standard in how pages and views should work in SPS 2003 / WSS.  We tried to change the SPS profile view with inheritance on another project (Armand will remember that one) but AFAIK we ended up writing our own implementation, it was a lot easier than trying to change the profile editor that came with SPS, even though we came close.  It was a very bad hack though and very unstable (The inherited version, not our own implementation! :D).  Hope they allow more flexibility in the next version of SPS.]

Posted by Pieter | with no comments
Filed under:

Skype

Yes there is a new version out of this amazing piece of software, get it here.

Skype has been an absolute godsend for me, I can now talk to friends and family all over the world at no extra cost.  I can even talk to people not connected to the internet at rates that are ten times less than normal international phone charges.  You do need some sort of broadband connection to use it effectively, I've tried speaking to my uncle who was on a 56k dial-up connection and we had some serious lag.  You can also subscribe to a voicemail service, so people can leave messages if you are out.  SkypeIn is a service that you can use where you can get your friends to phone a local number and then get connected to you through Skype.  Pretty cool from the guys who created KaZaa. 

Anyway I've been using skype for over a year now and it rocks.

Posted by Pieter | with no comments
Filed under:
More Posts Next page »