Saturday, July 26, 2008

I'm working on a media center application right now that I want to run kiosk style; topmost and fullscreen. This is amazingly simple to do in WPF, simply set the Topmost property to true, the WindowState property to Maximized and the WindowStyle to None.

.NET | .NET 3.5 | C# | WPF
Saturday, July 26, 2008 12:21:30 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Tuesday, June 17, 2008

Telerik has a very nice online code converter here. I've recently been converting VB.NET code to C# and this tool seems to be able to convert code that many of the others out there cannot. The only thing it seems to miss is the parens when converting indexer callers. So it doesn't convert the VB.NET myDataReader("Name") to the C# myDataReader["Name"]. Not a huge deal though.

Tuesday, June 17, 2008 6:54:22 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

Rick Strahl's .NET Rocks presentation on AJAX and jQuery (that he mentioned in May) has been published. Check it out.

.NET | AJAX | jQuery
Tuesday, June 17, 2008 3:49:31 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Wednesday, May 21, 2008

Reachmail (the company I work for) is looking for a senior ASP.NET/C# developer. If you are a progressive developer who is a true geek, really understands OO and patterns and is looking for a change, browse to the link below to apply. We are currently located in Naperville but will be moving to downtown Chicago the 1st of July (Within walking distance of Union and Ogilvie). We really need someone who knows their stuff and doesn't require hand holding. Although we need someone who is able to work independently we don't want an independent person (IE "cowboy"); they must be a team player or they wont last long. We have a relaxed environment and a lot of growth.

The software is a permission based email marketing SAAS written primarily in classic ASP with a SQL Server 2005 back end. Parts of the system are written in VB.NET and C#. One of our goals is to get the application converted over to ASP.NET/C# and rearchitect much of the system. All of our existing .NET code has been upgraded to 3.5 and new development is obviously in 3.5 and C#.

 

.NET | C#
Wednesday, May 21, 2008 3:42:58 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Wednesday, November 14, 2007

Evidently the aspnet_compiler.exe does not care about .refresh files (From my tests and what I read on the internets). It would be nice if it did as it would reduce the steps needed to build a WSP (Web Site Project) on a build server. I ended up just manually copying the assemblies into the bin folder before the build as follows in this nant script:

<mkiisdir dirpath="..\BabelFish.ServiceHost.Web" vdirname="BabelFish.ServiceHost.Web" />

<copy todir="..\BabelFish.ServiceHost.Web\bin">
    <
fileset basedir="..\BabelFish.Services\bin">
        <
include name="*.dll" />
    </
fileset>
</
copy>

<exec program="C:\WINDOWS\Microsoft.NET\Framework\${framework.version}\aspnet_compiler.exe" useruntimeengine="true">
    <
arg value="-p" />
    <
arg value="..\BabelFish.ServiceHost.Web" />
    <
arg value="-v" />
    <
arg value="BabelFish.ServiceHost.Web" />
</
exec>

<deliisdir vdirname="BabelFish.ServiceHost.Web" />

Wednesday, November 14, 2007 6:33:25 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Friday, November 09, 2007

I have been wanting to dig into F# for quite some time and finally got an opportunity. My first stab at it implements the calculation of kinetic energy given a weight in lbs, speed in mph and output in kJ. Pretty basic, but ya gotta start some where right? :)

KineticEnergy.zip (.95 KB)

// Get info from the user
do Printf.printf "Enter the weight (LBS): "
let m = read_line()
do Printf.printf "Enter the velocity (MPH): "
let mph = read_line()

// Pound to kilogram conversion
let kg lbs = lbs / 2.2

// Miles/h to Meters/s conversion
let mps mph = (((mph * 1.6) * 1000.0) / 60.0) /60.0

// Kinetic energy calculation
let Ek m v = (0.5 * m * (v * v)) / 1000.0

// Show me the money
do Printf.printf "\nEk = %fkJ\n\n" (Ek (kg (float_of_string m)) (mps (float_of_string mph)))

// Wait! Let me see the answer...
do Printf.printf "Press enter to continue..."
let x = read_line()

Friday, November 09, 2007 9:52:37 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Tuesday, October 09, 2007

I love WiX, but I hate that you have to specify the id's and short filenames! This really slows you down when you have a lot of files to add. I have read that these may be optional in v3 and auto generated by the compiler. Until then you could use this Visual Studio addin that that allows you to randomly generate and insert id's and short filenames as well as insert some common tags with the aformentioned attributes randomly filled in. n-joy!

Visual Studio 2005

Installer: WiXHelperAddin.EXE (217.21 KB)
Source: WiXHelperSource.zip (258.91 KB)

Visual Studio 2008

Installer: WiXHelperAddin2008.EXE (217 KB)
Source: WiXHelperSource2008.zip (63.89 KB)

PS: Also, check out the GUID inserter (Which also appears in the image below...); this is very helpful for WiX development!

image

Tuesday, October 09, 2007 1:41:54 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 

I do this often enough to forget how to do it (And where I've seen how to do it!). Rick Strahl has a nice post about adding icons to custom Visual Studio addins; the about box icon and the icons that appear in menus.

http://www.west-wind.com/WebLog/posts/3862.aspx

Tuesday, October 09, 2007 12:42:59 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Tuesday, September 18, 2007

Here is a simple method to invert an HTML color:

private static string InvertHTMLColor(string htmlColor)

{

htmlColor = htmlColor.Replace("#", string.Empty).Trim();

if (string.IsNullOrEmpty(htmlColor) || htmlColor.Length != 6)

     throw new ArgumentException("Invalid HTML color.");

return string.Format("#{0}{1}{2}",

     InvertChannel(htmlColor.Substring(0, 2)),

     InvertChannel(htmlColor.Substring(2, 2)),

     InvertChannel(htmlColor.Substring(4, 2)));

}

private static string InvertChannel(string channel)

{

channel = channel.Trim();

if (string.IsNullOrEmpty(channel) || channel.Length != 2)

     throw new ArgumentException("Invalid color channel.");

int a = int.Parse(channel.Substring(0, 1), System.Globalization.NumberStyles.HexNumber);

int b = int.Parse(channel.Substring(1, 1), System.Globalization.NumberStyles.HexNumber);

return (255 - ((16 * a) + b)).ToString("X");

}

.NET | C#
Tuesday, September 18, 2007 4:26:53 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [1]  | 
 Tuesday, August 21, 2007

Attached is the source for a simple TCP proxy server. I whipped it up pretty quickly so it probably needs some refactoring if you plan to use it in production. The server class is loosely based on the Cassini implementation. You can set the listen port and forward host/port in the app config:

<configuration>

    <appSettings>

        <add key="listenPort" value="443"/>

        <add key="forwardHost" value="wush.net"/>

        <add key="forwardPort" value="443"/>

    </appSettings>

</configuration>

image

TCPProxy.zip (24.81 KB)
Tuesday, August 21, 2007 5:42:09 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Tuesday, July 17, 2007

If you are programmatically updating the value of a lookup field and it doesn't seem to update, you need to trip "dirty" flag on that field. If you don't, SP wont know that the list item needs to be updated. Basically all you do is set the field to itself and this will mark the field as dirty. Here is an example:

SPFieldLookupValueCollection lookupValues;

lookupValues = (SPFieldLookupValueCollection)listItem["MyLookupField"];

lookupValues.Add(new SPFieldLookupValue(1, "SomeLookupValue"));

// Set the lookup field back to itself to mark it dirty

listItem["MyLookupField"] = lookupValues;

listItem.Update();

Tuesday, July 17, 2007 5:35:37 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Monday, July 16, 2007

The Stopwatch Class, another great .NET 2.0 feature I keep forgetting to use so I'll blog about it (And hopefully I'll remember ;)... This is a great class for performance monitoring, instead of declaring a start time and subtracting it from the end time, etc. The following snippet checks the performance difference in doing a square root and a tangent over a number of iterations. Internally, when the stopwatch is started, the ticks of the current time are set as the start timestamp. When it is stopped the start ticks and end ticks (Current time) are subtracted and the private elapsed time field (A Long) is updated. The elapsed field is only reset when you explicitly call Reset() as it is accumulative. The public Elapsed property conveniently returns a TimeSpan.

int iterations = 10000000;

 

Stopwatch stopwatch = new Stopwatch();

stopwatch.Start();

 

// Do something...

for (int index = 0; index < iterations; index++)

{ Math.Sqrt(index); }

 

stopwatch.Stop();

 

Console.WriteLine(string.Format("Square root took {0} " +

    "milliseconds for {1} iterations.",

    stopwatch.Elapsed.Milliseconds, iterations));

 

// Do something else...

stopwatch.Reset();

stopwatch.Start();

 

for (int index = 0; index < iterations; index++)

{ Math.Tan(index); }

 

stopwatch.Stop();

 

Console.WriteLine(string.Format(@"Tangent took {0} " +

    "milliseconds for {1} iterations.",

    stopwatch.Elapsed.Milliseconds, iterations));

 

Console.ReadKey();

Monday, July 16, 2007 4:19:51 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Friday, July 13, 2007

I have seen a lot of posts on this and they all say something along the lines of 'simply go and set the path to the base vhd...'. Well, being a Virtual Server user, it wasn't as obvious to do as it is with VPC.  To do it in VS you need to...

1) Copy the VS 2008 VM to a folder in your VS2005 path and add it.

2) Copy the base VM (Which can be downloaded here) to a folder in your VS2005 path.

image

3) Under "Virtual Disks" click "Inspect", select the VS2008 vhd and click "Inspect".

image

4) The "Parent virtual hard disk(s)" property will show a link indicating that the parent drive could not be found. Click this link to set the location of the drive.

image

image

5) Once selected, click "Update parent path", start the VM and Login with administrator/P2ssw0rd.

Friday, July 13, 2007 4:24:51 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Wednesday, July 11, 2007

Someone asked me how to enable the (Fully functioning) web designer in a class library. Honestly I think using a WAP is all you need to do. It will give you a fully functioning web designer and will generate a DLL. If you already have a class library project that you want to now add web pages and user controls too just follow the instructions here (Under the section "Creating a hybrid VSeWSS/WAP Project") but instead add the following ProjectTypeGuids element below (In green). This will turn your class library project into a WAP.

<PropertyGroup>

<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

<ProductVersion>8.0.50727</ProductVersion>

<SchemaVersion>2.0</SchemaVersion>

<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

<ProjectGuid>{26E7042F-79CF-4782-86E2-7D1C914E164A}</ProjectGuid>

<OutputType>Library</OutputType>

<AppDesignerFolder>Properties</AppDesignerFolder>

<RootNamespace>ClassLibraryWithWebDevelopment</RootNamespace>

<AssemblyName>ClassLibraryWithWebDevelopment</AssemblyName>

</PropertyGroup>

Wednesday, July 11, 2007 5:03:30 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Friday, July 06, 2007

Attached is a simple contact generator (And source) that creates random contact data in CSV format. The data generated, although random, is pretty realistic as address and phone numbers correspond correctly and other values are sampled from a realistic set of data. The data generated appears as follows:

"Index","Id","FirstName","LastName","FullName","Username","Username2","Password","Email1","Email2","Phone1","Phone2","Fax1","Fax2","Address1","City1","State1","Zip1","Address2","City2","State2","Zip2"
"1","{c0d4079c-50c7-4214-a094-b09d51b9d143}","Raven","Huddle","Raven Huddle","rhuddle","raven.huddle","13af04ae","raven.huddle@aol.com","raven.huddle@earthlink.net","(303) 998-8084","(718) 229-7963","(303) 998-5593","(718) 229-4928","84596 Brimm BLVD","Boulder","CO","80302","36863 Noakes LN","Flushing","NY","11364"
"2","{74e80927-a654-4010-9020-7098452b4193}","Rhonda","Reitz","Rhonda Reitz","rreitz","rhonda.reitz","3282e152","rhonda.reitz@btinternet.com","rhonda.reitz@verizon.net","(907) 252-0297","(703) 242-6715","(907) 252-0163","(703) 242-9363","89079 Sterrett PL","Soldotna","AK","99669","41346 Mccauley HWY","Vienna","VA","22181"
"3","{742a3ad4-e1e8-44ed-a6a0-1654981e0c9b}","Ruth","Mcnemar","Ruth Mcnemar","rmcnemar","ruth.mcnemar","16548a78","rmcnemar@aol.com","rmcnemar@verizon.net","(305) 541-2410","(704) 892-5466","(305) 541-4633","(704) 892-3899","93562 Bruno BLVD","Miami","FL","33129","45829 Meadowview HWY","Davidson","NC","28036"
"4","{d72fb280-66cf-49a8-81bb-f5da4a096614}","Jimmy","Kizer","Jimmy Kizer","jkizer","jimmy.kizer","3528671c","jkizer@verizon.net","jimmy.kizer@earthlink.net","(704) 854-4523","(734) 797-4218","(704) 854-9102","(734) 797-8335","98044 Meadows HWY, Suite 370","Gastonia","NC","28054","50311 Pamona LN","Livonia","MI","48150"
"5","{90409c90-c967-4b1f-b66c-6b9f31043303}","Kiehl","Gillum","Kiehl Gillum","kgillum","kiehl.gillum","18fa1042","kiehl.gillum@gmail.com","kiehl.gillum@rediffmail.com","(320) 679-6636","(810) 863-2970","(320) 679-3672","(810) 863-2871","2578 Claywood BLVD","Mora","MN","55051","54794 Rockledge PKWY, Suite 945","Roseville","MI","48035"
"6","{f47a479c-d0a9-43d8-84aa-97970b0c4892}","Walletta","Spivey","Walletta Spivey","wspivey","walletta.spivey","37cdece6","wspivey@hotmail.com","wspivey@bellsouth.net","(218) 723-8749","(650) 357-1721","(218) 723-8142","(650) 357-7306","7061 Baypointe AVE","Duluth","MN","55802","59277 Mack HWY","San Mateo","CA","94403"
"7","{f2b1687a-78ce-437b-baa0-2b959ee260d5}","Chauncey","Slemp","Chauncey Slemp","cslemp","chauncey.slemp","1b9f960c","cslemp@comcast.net","cslemp@charter.net","(412) 393-0962","(916) 492-0473","(412) 393-2712","(916) 492-1842","11544 Dumesnil CIR","Pittsburgh","PA","15222","63760 Tiburon PL, Suite 814","Sacramento","CA","95814"
"8","{19189dab-e300-42d2-8580-c4216fcaafb3}","Roxanne","Bond","Roxanne Bond","rbond","roxanne.bond","3a7372b0","roxanne.bond@msn.com","roxanne.bond@aol.com","(336) 506-3075","(308) 652-9124","(336) 506-7181","(308) 652-6278","16027 Continental CIR","Burlington","NC","27215","68242 Burning BLVD","Orleans","NE","67647"
"9","{7703a831-1f56-43cd-87ea-c998fcb52682}","Elvie","Cissell","Elvie Cissell","ecissell","elvie.cissell","1e451bd6","elvie.cissell@charter.net","ecissell@cox.net","(917) 344-5189","(770) 242-7876","(917) 344-1751","(770) 242-0814","20509 Tivoli RD, Suite 491","New York","NY","10041","72725 Perlman LN","Norcross","GA","30071"
"10","{0aed5fd3-70e8-41e0-bbc4-418d122a590b}","Newman","Peters","Newman Peters","npeters","newman.peters","216c4fb","npeters@earthlink.net","npeters@hotmail.com","(719) 530-7302","(281) 944-6628","(719) 530-6221","(281) 944-5249","24992 Oak LN","Salida","CO","81201","77208 Bolsa BLVD","Houston","TX","77037"

Installer: SetupContactGenerator.EXE (833.81 KB)

Source: ContactGeneratorSource.zip (584.5 KB)

Friday, July 06, 2007 3:29:07 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Thursday, July 05, 2007

I must say, the OOB development experience in SharePoint has been less than desirable. I feel like MS has given us a number of tools but left us in the lurch figuring out how to use them, and its not always obvious how. One thing I have wanted to do is use the designer to develop web parts and deploy them with the click of a button. The VSeWSS have made the "deploy with the click of the button" part possible but the designer part has not been so obvious. How can you marry a designer experience with the VSeWSS ease of solution deployment? I'll show you how...

For Starters

The following information utilizes the Visual Studio Extensions for WSS (VSeWSS) which can be downloaded here. VSeWSS only offers a subset of the features available with solution deployment but offers "one touch" deployment OOB. Creating your own solutions manually will give you more options but may be more work than its worth (Unless you have found some nifty 3rd party tool or created your own). So the following information will strictly use what VSeWSS has to offer. VSeWSS can only run on a Windows Server 2003 box with MOSS 2007 & Visual Studio 2005 installed (Although it can be hacked to run on XP, most of the features do not work). VSeWSS may have problems if MOSS 2007 was not installed as a standalone server, so says the download notes and my experience with it. Although I have a colleague who has used it in a farm configuration and not had an issue.

Creating a blank VSeWSS Project & Web Part

Obviously you cant use the designer with a web part but you can with a Web User Control (This is the thought behind SmartParts). So lets start off by creating a project from an empty VSeWSS template.

image

Next add a new Web Part from the VSeWSS templates.

image

Now your probably thinking "Now add a Web User Control, yada yada yada", right? Wrong! If you have gone down this path before you will probably discover a couple of things; first the Web User Control is not available as a new item in a VSeWSS project. This can be worked around fairly easily by modifying the templates available to the class library project type or by creating the user control in a Web Application Project (WAP) and copy the files over, either way hacky. Second, you will discover that the designer does not behave as it does in a WAP or web site. For example your code behind and designer classes are not linked together and when you double click a control the default event code is generated in the ascx file instead of the code behind. This and a number of other quirks render this method almost as bad as just coding your entire control in the Web Part (Almost, but not quite). So how do we get the designer to work properly? .

Creating a hybrid VSeWSS/WAP Project

We need to create a hybrid VSeWSS/WAP project. This requires that you either have VS2005 SP1 installed or the WAP extensions installed (If you decided not to wait 5 hours for SP1 to install...). In order to make your VSeWSS project also a WAP project you will need to adjust the project type in the .xxproj file. To do this, right click the project we just created an select "Unload Project". It may ask you to save, press yes.

image

Once the project is unloaded, right click it again and select "Edit xxxxxxxxxxx.xxproj".

image

Once you have opened the project file you will need to add in the WAP guid into the ProjectTypeGuids element under the first PropertyGroup. This guid, {349c5851-65df-11da-9384-00065b846f21}, should be the second guid in the list (Shown in bold/green below), the first one being the VSeWSS project guid. All the guids in this element should be separated by a semicolon as shown below.

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>

    <ProductVersion>8.0.50727</ProductVersion>

    <SchemaVersion>2.0</SchemaVersion>

    <ProjectGuid>{7A3CF036-DC02-4868-8CBA-A88E75552372}</ProjectGuid>

    <ProjectTypeGuids>{9E5D3E2D-E4E2-418e-8D80-2F0DA9A94F9A};{349c5851-65df-11da-9384-00065b846f21};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>

    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>

    <OutputType>Library</OutputType>

    <RootNamespace>MyGroovySharePointLibrary</RootNamespace>

    <AssemblyName>MyGroovySharePointLibrary</AssemblyName>

    <SignAssembly>true</SignAssembly>

    <AssemblyOriginatorKeyFile>Properties\Temporary.snk</AssemblyOriginatorKeyFile>

  </PropertyGroup>

 After this has been set, right click the the project again and select "Reload Project". Click yes to save when prompted.

image

Now close out of Visual Studio, save your project when prompted. Restart Visual Studio and open your project.

VSeWSS Deployment

Now your probably thinking "Now add a Web User Control, yada yada yada", right? Well, yes, you can now add a Web User Control and its designer will work properly. But we want to be able to deploy it strictly with VSeWSS and its solution builder. In order to do this we will need to install the user control with a Module, so lets do that first. Right click your project and add a new Module. I will generically call it UserControls as I will want to add more user controls to it as I add web parts.

image

Once your module is created you can delete the "sample.txt" file from the UserControls folder. Now right click the UserControls folder and click Add --> New Item and select the standard Web User Control.

image

Next open the module.xml in the UserControls folder and add a reference to your newly created user control.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <Module Name="UserControls" Url="UserControls" Path="">

    <File Url="MyGroovyUserControl.ascx" />

  </Module>

</Elements>

The Url attribute in the Module element specifies the relative path on the SharePoint site where the file will be deployed to. In this case I chose a sub folder called "UserControls".

Creating the User Control and Linking the Web Part

Now, add a label to your User Control called CurrentTime (Or whatever you want to call it...). And set it, in the control load event, to the current time.

namespace MyGroovySharePointLibrary.UserControls

{

    public partial class MyGroovyUserControl : System.Web.UI.UserControl

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            CurrentTime.Text = DateTime.Now.ToString();

        }

    }

}

Since the VSeWSS Solution Builder creates a solution that installs only the project assembly to the GAC (Which is lame indeed) you will need to add an assembly directive to the user control, before the control directive is defined. If you do not add it before the control directive your control will fail to load as it will not have a reference to the project assembly in the GAC.

<%@ Assembly Name="MyGroovySharePointLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5" %>

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="MyGroovyUserControl.ascx.cs" Inherits="MyGroovySharePointLibrary.UserControls.MyGroovyUserControl" %>

<asp:Label ID="CurrentTime" runat="server" Text="Label"></asp:Label>

To obtain the public key token you can run the sn.exe utility in the SDK with the -T parameter and the path to the assembly. For example:

image

Next, override the CreateChildControls method of your web part and load the user control with the Page.LoadControl method. UPDATE: Thanks to Charles for pointing out that you also need to remove (If your not using it) the default Render(...) override. The WebPart template has this defined and by default it does not call the base implementation so ya get nothing displayed!

namespace MyGroovyWebPart

{

    [Guid("cc2a1b52-324a-4a20-bca8-0d512f8348b4")]

    public class MyGroovyWebPart :

        System.Web.UI.WebControls.WebParts.WebPart

    {

        public MyGroovyWebPart()

        {

            this.ExportMode = WebPartExportMode.All;

        }

 

        protected override void CreateChildControls()

        {

            string userControl = "/UserControls/MyGroovyUserControl.ascx";

            try

            {

                Controls.Add(this.Page.LoadControl(userControl));

            }

            catch (Exception exception)

            {

                string message = string.Format("{0} failed to load: {1}",

                    userControl,

                    exception.Message);

                Controls.Add(new LiteralControl(message));

            }

        }

    }

}

Now hit F5 and deploy!

image

As you can see, this method gives you the benefit of the designer and VSeWSS solution deployment. The full source of the sample can be downloaded here:

MyGroovySharePointLibrary.zip (417.78 KB)
Thursday, July 05, 2007 5:18:06 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [8]  | 
 Tuesday, June 26, 2007

Normally I like to create a stand alone, abstract BLL assembly that can be used by multiple components (ASP.NET, WinForms, Windows Service, etc), nothing new, standard procedure. Well the VSeWSS Solution builder will only load and reference the VSeWSS project assembly in the SharePoint Solution. Pretty lame if you ask me! You would think that it would package all referenced assemblies not just the project assembly, how hard is that?? So you ether have to house all your code in the VSeWSS assembly or deploy referenced assemblies separately to the SP web front ends. If you forget about this, any code that tries to call code in the referenced assembly will throw a generic "File Not Found" exception in SP.

I sincerely hope there is a newer version of VSeWSS coming down the pike. It has the potential to be a really great tool for SP development but the limitations I keep encountering are seriously lessening its value. This is just another example of that.

Tuesday, June 26, 2007 8:42:04 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Friday, June 22, 2007

Another SharePoint anomaly... Will they ever end??? So I have had this strange issue where doing a deploy of a VSeWSS project does not seem to update the SharePoint site for certain elements like schemas. I have to retract/remove the solution manually from SP, close/reopen Visual Studio (Otherwise I would get a null ref error), then redeploy to see changes. The VSeWSS deploy process does an iisreset (Which I tried manually doing as well) but the updates do not appear without following the steps mentioned. I checked the SP database and SP hive and the elements in question were deployed... So the only thing I could think of is that these elements must cached in memory, which was baffling since an iisreset should clear that out (Right?). Well I finally got the bright idea to verify that iisreset was in fact closing out the IIS service process completely. And lo an behold it was not! After further investigation I found that the “Windows Remote Management (WS-Management)” service, which depends on IIS, was preventing a complete exit of the inetinfo process. I'm not sure what the iisreset was actually doing all along (It said it successfully reset the IIS services), possibly just recycling the AppDomain(s)? But in that case wouldn't SP release cached elements upon termination of the AppDomain(s)? Not really sure, but what I am sure of is that stopping and disabling the the WRM service allowed inetinfo to completely close when the service was restarted by iisreset. And voilà! My changes!

Incidentally I am running Virtual Server 2005 which is monitored by the "Virtual Machine Manager Agent" service. This service depends on the WRM service. So disabling the WRM service will disable your VMMA service. You might want to let your network admin know you need this disabled or it might reappear.

Friday, June 22, 2007 9:22:26 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Monday, June 18, 2007

This error almost drove me over the edge... The SharePoint properties pane in Visual Studio would show the error "An error occured trying to load the page. Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)"

image

 

After pulling much of my hair out (And doing some trial & error testing) I realized that the problem was that the pane was looking to see if there were any new web parts added to the project each time it loaded. I had added an abstract WebPart base class which some of my other WebParts would inherit from. Problem was this abstract WebPart class was not decorated with the Guid attribute, which is evidently required by the SharePoint property page. I added the Guid attribute and the error goes away.

 

[Guid("9D5AFDE3-F3A3-4947-AC6F-5D66CEF0D2F6")]

public abstract class ListBoundWebPart : System.Web.UI.WebControls.WebParts.WebPart

{ ... }

The only problem is this WebPart base class is now included in the SharePoint Solution as a feature. I haven't found a way as of yet to exclude it.

Monday, June 18, 2007 4:16:21 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Wednesday, June 06, 2007

Having just built a couple of VS2005 addins I wanted to share a couple of resources that really helped me:

Creating Menu Bitmaps and AboutIcons for Add-ins in Visual Studio .NET 2005
Creating a CommandBar and adding Commands to it in a VS.NET Add-in
Visual Studio 2005 Automation Samples

Hopefully when I get more time I can post a walk through. Many thanks to Rick Strahl who seems to always have good info on how to do advanced development in .NET! 9 times out of 10 I'll find something on his blog/site, great resource!

Wednesday, June 06, 2007 7:07:19 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Thursday, April 12, 2007

So I am trying to write log information to an XML document using the XmlTextWriter.  When it reaches a certian size I want it closed out and archived. What I mean by "closed out" is that while the log file is "open" the root element is not closed so that I can keep adding entries over a period of time. In other words:

<?xml version="1.0"?>
<log>
    <entry date="1/1/2007">Yada yada yada</entry>
    <entry date="1/1/2007">Yada yada yada</entry>
    ...


Then once its full I will write the closing root element and rename it:

<?xml version="1.0"?>
<log>
    <entry date="1/1/2007">Yada yada yada</entry>
    <entry date="1/1/2007">Yada yada yada</entry>
    ...
    <entry date="1/1/2007">Yada yada yada</entry>
</log>

Well the XmlTextWriter automatically closes out all open elements when you close it. Looking in Reflector reveals what is happening behind the scenes:

public override void Close()
{
   try
   {
      this.AutoCompleteAll();
   }
   catch {}
   finally
   {
      this.currentState = State.Closed;
      this.textWriter.Close();
   }
}

First the AutoCompleteAll() method is called, then the underlying stream is closed. The AutoCompleteAll() method is as follows:

private void AutoCompleteAll()
{
   if (this.flush)
   {
      this.FlushEncoders();
   }
   while (this.top > 0)
   {
      this.WriteEndElement();
   }
}

Doesent look like there is any official way to explicitly close only the elements you want to close, its just automatically done for you when you close the writer. The only work around I could figure out is to explicitly close the elements I want closed, then close the base stream (Not the XmlTextReader). This works but IMO its a little hackey since the code in the Close() method could potentially change in the future and you could end up circumventing some code that you might want executed when your done with the reader.

.NET | C# | VB.NET | XML/XSL
Thursday, April 12, 2007 7:01:42 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Friday, March 23, 2007

I have been working with the new custom configuration classes in .NET 2.0 and they really make creating custom xml configuration a snap. They are a little quirky to use at first but once you get past the initial learning curve they really make the job a lot easier.

One thing I really wanted to figure out is how to use these new classes to read files other than the default app/web.config. For example if you have one config file that might be shared between exes or if a config file is pulled from a URL. Its actually pretty easy to do.

First create your custom configuration file. It will look exactly the same as a web/app.config file except it will only contain your custom section(s). Create a section handler element identifying the custom section handler and the name of the section. Again, nothing different from doing this in the app/web.config.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
  <section name="mySettings" type="CustomConfigHandler.MySettingSection, CustomConfigHandler"/>
 </configSections>
 <mySettings>
  <someSetting someAttribute="This is an attribute value from Settings1.config"/>
 </mySettings>
</configuration>

Next create a Configuration object that points to your file by passing in an ExeConfigurationFileMap with the ExeConfigFilename set.

// Create an exe file map containing the path to your config file
ExeConfigurationFileMap FileMap = new ExeConfigurationFileMap();
FileMap.ExeConfigFilename = "MySystem.config";

// Create a configuration object that is tied to your custom config file.
Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(FileMap, ConfigurationUserLevel.None);

// Create the custom config section handler
MySettingSection MySettings = (MySettingSection)Config.GetSection("mySettings");

Console.WriteLine(MySettings.SomeSetting.SomeAttribute);


The entire source can be downloaded here:

ExternalConfigFile.zip (40.24 KB)
.NET | C# | Configuration | VB.NET
Friday, March 23, 2007 8:30:17 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Wednesday, February 14, 2007

I had a baffling problem arise today. Here is the scenario; I have a .NET WinForms app with a WebBrowser control. The WebBrowser control loads a web page that contains an embedded Flash movie. I need to send keystrokes to the Flash movie from the WinForms app. Now MS provides the SendKeys class under the Windows.Forms namespace for this very purpose, but in this instance it doesent pass them on to the Flash movie (Although it does pass them to HTML elements in the page). Hmmmmmm... A little digging in Reflector uncovers the reason. The SendKeys class internally calls the SetKeyboardState() native method to send the keyboard input. Here is what MSDN says about that call:

The SetKeyboardState function copies a 256-byte array of keyboard key states into the calling thread's keyboard input-state table. This is the same table accessed by the GetKeyboardState and GetKeyState functions. Changes made to this table do not affect keyboard input to any other thread.

I'm no expert on how embedded ActiveX controls work within a web page in IE but I bet the Flash control is not running in the same thread as the browser UI. And in the case of using the WebBrowser control, not in the UI thread of the WinForms app. So SendKeys will not be able to send keystrokes to embedded Flash in a WebBrowser control. Just a guess, but it seems that is what is happening here. Well, scratch that, I just checked Spy++ and everything is running under the WinForm UI thread including the Flash ActiveX control. So at this point I have no idea why SendInput() works but SetKeyboardState() doesent (And thus the SendKeys class), very strange indeed! If anyone knows for sure, please leave a comment! :)

So the other option is calling the SendInput method. FYI, this method supersedes the keybd_event method. Here is a sample of the code required to send keystrokes to the foreground window. Remember, you must make sure that the WebBrowser control has focus for it to receive the keystrokes (As does the Flash control in the web page, see further down for more info).

private void Main_Load(object sender, EventArgs e)
{
    WebBrowserControl.Navigate(@"file://C:\Temp\Flash.html");
    Timer.Enabled = true;
}

private int Index = 0;

private void Timer_Tick(object sender, EventArgs e)
{
    Index++;

    NativeMethods.INPUT[] structInput = new NativeMethods.INPUT[1];

    structInput[0] = new NativeMethods.INPUT();
    structInput[0].type = NativeMethods.INPUT_KEYBOARD;
    structInput[0].ki.wScan = 0;
    structInput[0].ki.time = 0;
    structInput[0].ki.dwFlags = 0;
    structInput[0].ki.dwExtraInfo = NativeMethods.GetMessageExtraInfo();
    structInput[0].ki.wVk = NativeMethods.VK