mike-obrien.net Curriculum Vitae Blog Labs
Friday, January 02, 2009

While reading CLR via C# I picked up a couple of interesting tidbits about the using block that I never realized. First you can declare/instantiate multiple objects as long as they are of the same type and second you can pass in objects that have been declared outside the block. Not sure how useful these would be but interesting none the less. I think more useful would be allowing the developer to declare/instantiate multiple objects of different types.

class Program
{
    static void Main(string[] args)
    {
        Stuff stuff = new Stuff();

        using (
            Stuff stuff1 = new Stuff(),
            stuff2 = new Stuff(),
            stuff3 = stuff)
        {
        }
    }
}

class Stuff : IDisposable
{
    #region IDisposable Members

        public void Dispose() { }

    #endregion
}
.NET | .NET 3.5 | C#
Friday, January 02, 2009 10:23:04 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Tuesday, November 18, 2008

One thing I really love about Linq is how succinctly you can write import and export code. I've had to do this many times before Linq and it always felt kludgy no matter how clean you did it (Especially building xml documents). I think the decision to bake a set based syntax into C# and VB.NET was a great idea. So here is yet another Linq code sample, aren't there already a million of them out there??

Exporting data from a SQL Server table to xml using Linq2Sql and Link2Xml:

TestDataContext dataContext =
    new TestDataContext(@"Data Source=localhost;
        Initial Catalog=Test;Integrated Security=True");

XDocument export = new XDocument(
    new XElement(
        "clients",
            new XComment("This is a comment!"),
            from client in dataContext.Clients
            orderby client.State, client.City 
            select new XElement(
                "client",
                    new XAttribute("id", client.Id.ToString()),
                    new XElement("name", new XText(client.Name)),
                    new XElement("address", new XText(client.Address)),
                    new XElement("address2", new XText(client.Address2)),
                    new XElement("city", new XText(client.City)),
                    new XElement("state", new XText(client.State)),
                    new XElement("zip", new XText(client.Zip)),
                    new XElement("comments", new XCData(
                        string.Format("{0} is based out of {1}.", 
                        client.Name, client.State)))
                )
            )
        );
export.Save(@"D:\Temp\Clients.xml");

Importing data from an xml document to a SQL Server table using Linq2Xml and Linq2Sql (And as Anon pointed out we can do a direct cast since the XAttribute (And XElement) class define explicit conversion operators for primitive types. On that note we also dont need to check if the XElement or XAttribute is null. The Linq2Sql entity defines fields (Or properties) as nullable types and the XElement and XAttribute classes define conversion operators for nullable primitive types. So if an attribute or element does not exist the entity value is simply set to null.):

TestDataContext dataContext =
    new TestDataContext(@"Data Source=localhost;
        Initial Catalog=Test;Integrated Security=True");

XDocument document = XDocument.Load(@"D:\Temp\Clients.xml");

var clients = from client in document.Element("clients").Elements("client")
    select new Client()
    {
        Id = (int)client.Attribute("id"),
        Name = (string)client.Element("name"),
        Address = (string)client.Element("address"),
        Address2 = (string)client.Element("address2"),
        City = (string)client.Element("city"),
        State = (string)client.Element("state"),
        Zip = (string)client.Element("zip")
    };

foreach (var client in clients)
    dataContext.Clients.InsertOnSubmit(client);

dataContext.SubmitChanges();
Tuesday, November 18, 2008 2:10:56 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [2]  | 
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]  | 
Thursday, June 19, 2008

I never realized this but you can set the default SMTP information in the .config file (Thanks Viktar!). This applies to the new System.Net.Mail.* classes (Not the deprecated System.Web.Mail.* classes). MSDN defines the elements here and here.

<configuration>
  <system.net>
    <mailSettings>
      <smtp deliveryMethod="network" 
         from="appointments@TrepanationNation.com"> <network host="smtp.TrepanationNation.com"
         port="25" defaultCredentials="true"/> </smtp> </mailSettings> </system.net>

The code is the same but you no longer have to specify the from and SMTP server details:

using (MailMessage message = new MailMessage())
{
    message.IsBodyHtml = true;
    message.To.Add("someguy@someserver.com");
    message.Subject = "Trepanation Appointment";
    message.Body = @"<b>This confirms your 
        Trepanation appointment this Friday.</b>";
    SmtpClient mailClient = new SmtpClient();
    mailClient.Send(message);
}
.NET 2.0 | C# | SMTP
Thursday, June 19, 2008 2:56:35 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]  | 
Tuesday, May 06, 2008

Parsing a date with a custom format is as easy as pie with the DateTime.ParseExact method, check it:

DateTime.ParseExact("04292008", "MMddyyyy", null)

Where the first parameter is the value to parse, the second is a format string and for the culture info you can pass null for the current culture (Unless you need to specify one).

UPDATE:

If you need to exclude other characters in the string you can add the literal values qualified by single quotes in the format string. So for example lets say you wanted to extract the date and hour from an IIS log filename, ex08041013.log. You could pass the format string 'ex'yyMMddHH'.log' and the parse method will ignore the ex and .log portions of the string.

DateTime.ParseExact("ex08041013.log", "'ex'yyMMddHH'.log'", null)
C#
Tuesday, May 06, 2008 8:46:21 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Monday, February 11, 2008

I cant believe I wasn't aware of this cool little feature but with the release of C# 2.0 came the yield keyword. Basically it allows you to create an enumerator that "yields" when it has the current value ready. It's much simpler and elegant than enumerator code you would normally have to write. As an example we will create an enumerable class that returns numbers in the Fibonacci sequence.

public class FibonacciSeries : IEnumerable
{
    int size;

    internal FibonacciSeries(int size)
    { this.size = size; }

    public IEnumerator GetEnumerator()
    {
        int termA = -1;
        int termB = 1;

        for (int index = 0; index < size; index++)
        {
            int current = termA + termB;
            termA = termB;
            termB = current;
            yield return current;
        }
    }
}

Instead of creating a separate class that implements IEnumerable and keeps track of iterator state, we simply put our enumerator code in the GetEnumerator() method and call yield return ...; when we have a value ready. This allows the iterator to be written as if we were pushing the value out, much cleaner and simpler. Behind the scenes, when our code is compiled, the compiler builds what we would have normally had to write . Below is the compiled version of the above code in Reflector (Albeit cleaned it up a bit):

public class FibonacciSeries : IEnumerable
{
    private int size;

    internal FibonacciSeries(int size)
    {
        this.size = size;
    }

    public IEnumerator GetEnumerator()
    {
        Enumerator enumerator = new Enumerator(0);
        enumerator.parent = this;
        return enumerator;
    }

    private sealed class Enumerator : IEnumerator<object>, IEnumerator, IDisposable
    {
        private int state;
        private object current;
        public FibonacciSeries parent;
        public int currentValue;
        public int index;
        private int termA = -1;
        private int termB = 1;

        public Enumerator(int state)
        {
            this.state = state;
        }

        public bool MoveNext()
        {
            switch (this.state)
            {
                case 0:
                    this.index = 0;
                    break;

                case 1:
                    this.index++;
                    break;
            }

            this.state = -1;

            while (this.index < this.parent.size)
            {
                this.currentValue = this.termA + this.termB;
                this.termA = this.termB;
                this.termB = this.currentValue;
                this.current = this.currentValue;
                this.state = 1;
                return true;
            }

            return false;
        }

        void IEnumerator.Reset()
        { throw new NotSupportedException(); }

        void IDisposable.Dispose() { }

        object IEnumerator<object>.Current
        { get { return this.current; } }

        object IEnumerator.Current
        { get { return this.current; } }
    }
}
C#
Monday, February 11, 2008 1:43:21 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
Monday, January 28, 2008

Mike Jones has posted an analysis of an adaptation of the Concurrent Life app (That ships with the F# distro) here. I haven't gotten through the entire article yet but so far it is great. The sample app has a C# interface and consumes an F# library. He suggests that C#'ers not familiar with functional programming use F# imperatively to get comfortable with the language syntax then tackle the functional style.

Also, I came across these articles by Thomas Petricek that are proving very helpfull:

  • F# Overview (I.) - Introduction
  • F# Overview (II.) - Functional Programming
  • F# Overview (III.) - Object Oriented and Imperative Programming
  • F# Overview (IV.) - Language Oriented Programming
  • And also a nice intro by The Flying Frog Consultancy...

    C# | F#
    Monday, January 28, 2008 4:38:04 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
    Tuesday, November 13, 2007

    I have gotten the following exception a couple of times:

    Service 'Translator' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element.

    There are a number of things that could potentially cause this exception but the one that has gotten me a couple of times is making sure the name attribute of the service element in the .config contains the fully qualified class name. So for example if I have the following service:

    namespace BabelFish.ServiceHost.Web
    {
        public class Translator : BabelFish.Services.Translator
        {
        }
    }

    The service name should be as follows (in bold):

    <configuration>
        <
    system.serviceModel>
            <
    services>
                <
    service behaviorConfiguration="TranslatorBehavior" name="BabelFish.ServiceHost.Web.Translator">
                    <
    endpoint address="http://localhost/BabelFish.ServiceHost.Web/Translator.svc" binding="wsHttpBinding" name="Translator" contract="BabelFish.Services.Contracts.Service.ITranslator"/>
                   <
    endpoint address="mex" binding="mexHttpBinding" name="MetaDataExchange" contract="IMetadataExchange"/>
                </
    service>
            </
    services>
            ...
        </system.serviceModel>
        ...
    </configuration>
    Tuesday, November 13, 2007 4:36:39 PM (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]  | 
    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]  | 
    Thursday, June 07, 2007

    If you have worked much with WSS and the many XML definition files that accompany it you will no doubt be generating a lot of guids. The "Tools|Create GUID" can be a bit cumbersome so I searched for an alternative and couldn't find one. So I wrote a simple GUID insert AddIn that adds three links to your editor context menu to insert guids in different formats. First a standard guid; "6D7C589A-DDBB-4B01-BCEE-6F921885F942", second an undecorated guid; "AFCE87A3021C4BF7A51078DFA1F73995" (Good for content type ID's), and third a "registry" guid; "{0E0057DF-B8EC-44E3-A9AA-3EDBFEA7025B}". The setup installs the source as well if you want to modify it.

    Visual Studio 2005

    Installer: InstallInsertGUIDAddin.EXE (288.28 KB)

    Visual Studio 2008

    Installer: InstallInsertGUIDAddin2008.EXE (234.92 KB)
    Source: InsertGUIDAddinSource2008.zip (101.51 KB)

    Thursday, June 07, 2007 5:10:08 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_RIGHT;

        // Key up every other pass
        if (Index % 2 == 0)
        {
            structInput[0].ki.dwFlags = NativeMethods.KEYUP;
        }

        NativeMethods.SendInput(1, structInput, Marshal.SizeOf(structInput[0]));
    }

    The basic native method & struct declarations are as follows. PInvoke.NET has a nice definition of all of these.

    public const int INPUT_KEYBOARD = 1;
    public const int KEYUP = 2;

    public const int VK_LEFT = 0x25;
    public const int VK_UP = 0x26;
    public const int VK_RIGHT = 0x27;
    public const int VK_DOWN = 0x28;


    [StructLayout(LayoutKind.Sequential)]
    public struct MOUSEINPUT
    {
        int dx;
        int dy;
        int mouseData;
        int dwFlags;
        int time;
        IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct KEYBDINPUT
    {
        public short wVk;
        public short wScan;
        public int dwFlags;
        public int time;
        public IntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct HARDWAREINPUT
    {
        int uMsg;
        short wParamL;
        short wParamH;
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct INPUT
    {
        [FieldOffset(0)]
        public int type;
        [FieldOffset(4)]
        public MOUSEINPUT mi;
        [FieldOffset(4)]
        public KEYBDINPUT ki;
        [FieldOffset(4)]
        public HARDWAREINPUT hi;
    }

    [DllImport("user32.dll", SetLastError = true)]
    public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

    [DllImport("user32.dll", SetLastError = false)]
    public static extern IntPtr GetMessageExtraInfo();

    The only other thing you need to do to make this completely automated is to set focus on the Flash movie in the web page using JavaScript. Simply call the focus method of the Flash control as follows:

    window.document.MyFlash.focus();

    The entire project can be downloaded here.

    .NET | C# | Flash | Win32 API
    Wednesday, February 14, 2007 10:31:15 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [4]  | 
    Monday, January 29, 2007

    There is a new version of the Hid Library in the labs. It has been converted to .NET 2.0 and includes a bug fix. This bug fix involved how the vendor and product id were cast in the structure consumed by the Hid API. So some devices like Logitec's gamepads would not be recognized by their product and vendor id's. Now that issue is resolved. N-joy!

    USB Hid Device Library

    .NET | C# | USB HID | VB.NET
    Monday, January 29, 2007 10:36:12 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [27]  | 
    Tuesday, January 09, 2007

    I was looking over a peice of my code toda