Rss 2.0 via FEED
Ken Hughes... - NET
Productivity, Technology and Automating Everything...
    
 

image Recently I have been working with DotNetNuke. This is a superb open source CMS platform running on ASP.NET with a SQL back end, simple to install, easy to use and there is a thriving community around it. It is also available in a ‘Professional’ version which costs around £2000 per year and provides additional workflow features, a support contract and various other benefits.

image I choose not to go for the pro version, just because I don’t see much point in having some aspects of a website/webapp covered with a support agreement, but not others (any third party controls/extensions are not covered, and I had bought the excellent DataSprings Suite and was using multiple components from it).

Anyway, when I had everything working the way I wanted, I started to look at performance. There are many websites providing tools and tips around maximizing performance of DNN sites – this includes caching strategies, output compression, turning off none essential ‘housekeeping tasks’ and the like.
One of the tweaks (for low traffic sites) was to ‘kick’ the site every few minutes to ensure that IIS does not unload it (and therefore need to spin it up again the next time someone visits – this can take a good few seconds).image

  My initial thoughts were around a scheduled PowerShell command – simple to come up a one liner to request a page and thus keep the web app in memory.

(new-object “System.Net.WebClient”).DownloadString(“http://www.website.com/”)

Then I thought I might have it ‘kick’ a few websites, and make it configurable, so I started thinking ‘Windows Service’. It turns out that there are a load of these apps and services available to buy, some targeted specifically at DNN, some more generic. Reluctant to spend $20/year on a service I decided to craft my own.

It is basically a windows service, that reads an XML file for a timeout and a list of urls to kick. It implements a 1 second timer and counts down the timeout value, when it reaches 0 it kicks each of the urls (recording how long the response took). I haven’t done anything with the measured response time, but it would be fairly easy to write out to a DB or file for later analysis…

Here is a .zip file with everything you need – binaries, sample configuration file, install instructions and full source. It is Creative Commons license so knock yourself out.

WebAppKeepAlive.zip

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Saturday, September 26, 2009 10:30:41 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | ASP.NET | C Sharp | Development | Software | Web

Yesterday on Leon's Blog, secretGeek, I noticed they had released v3.4 of TimeSnapper. One of the features that caught my eye was the ability to develop/add plugins to it.timesnapper_screen

I love plugins, I've written plugins for Windows Live Writer, Outlook, dasBlog, and more.  Everything should have an SDK or plugin'able architecture. I championed it at work and we were one of the first Archiving Vendors with a 'real' SDK (I've built demo Vista Gadgets, integration scripts, federated search providers and PowerShell commandlets for it).

Anyway, the TimeSnapper plugin model looked really clean and easy to use. Read the one page description and your ready to go (didn't even download the sample code - it was so clear how things worked there was no need).

twitpic_logoI wanted a little play around with it, so I though upload a snapshot to TwitPic would be a good idea. Opening a new project in Visual Studio, adding a reference to the ITimeSnapperPlugin.dll, create a new inherited class from ITimeSnapperPlugin and implement the interface :

 

    #region ITimeSnapperPlugin Members

    bool ITimeSnapperPlugin.Configurable
    {
        get { return true; }
    }

    void ITimeSnapperPlugin.Configure()
    {
        System.Windows.Forms.Form frm = new TwitPicPluginConfig();
        frm.ShowDialog();
    }

    string ITimeSnapperPlugin.Description
    {
        get { return "Uploads snapshots to TwitPic"; }
    }

    string ITimeSnapperPlugin.FriendlyName
    {
        get { return "TwitPic Plugin"; }
    }

    object ITimeSnapperPlugin.HandleEvent(TimeSnapperEvent TimeSnapperEvent, EventArgs args)
    {
        switch (TimeSnapperEvent)
        {
            case TimeSnapperEvent.SnapshotSaved :
                // upload it it to TwitPic
                if (IsTimeToUpload())
                {
                    string fileName = ((TimeSnapperPluginAPI.SnapshotSavedEventArgs)(args)).Activity.Filename;
                    Debug.WriteLine("Uploading " + fileName + " to TwitPic");
                    XmlDocument xmlDoc = UploadToTwitPic(fileName);
                }
                break;

            default :
                Debug.Assert(false, "Should never occur");
                break;
        }
        return null;
    }

    TimeSnapperMenuItem[] ITimeSnapperPlugin.MenuItems()
    {
        return null;
    }

    Guid ITimeSnapperPlugin.PluginID
    {
        get { return new Guid("50744334-C5A0-44f1-BE64-5BBF32FDA79D"); }
    }

    TimeSnapperEvent[] ITimeSnapperPlugin.SubscribesTo()
    {
        return new TimeSnapperEvent[] { TimeSnapperEvent.SnapshotSaved };
    }

 

All that was required was to give it a new Guid and name/description and then subscribe to the 'SnapShotSaved' event and handle the event when it was triggered.yedda_logo
To get the image uploaded to TwitPic I used some code from the excellent Yedda Twitter C# Library (just the stuff for posting image data to a url).
That all worked a breeze, but it was sending images (and posting to my twitter account) every 10 seconds (and of course it was hard coded to my username/password) - what was needed was a bit of configuration...

Luckily the plugin model provides an excellent and easy way to do this (set the Configurable property to true, and handle the Configure event). A bit more jiggery pokery, one modal dialog and an XML config file later, it was all working (configurable username, password, twitter message and frequency of updates) - although I really should do something better than store the username/password in clear text in an XML file...

If you want the plugin, just drop this dll into your %install%\plugins folder and restart TimeSnapper.

GEO: 51.4043006896973 : -1.28754603862762

Share/Bookmark

Posted: Wednesday, March 18, 2009 12:32:14 PM (GMT Standard Time, UTC+00:00)  #   Comments [2]
TAGS: .NET | C Sharp | Development | Software | Twitter

handheldgps Apparently I am rapidly becoming 'Geo Guy'. I seem to be adding Geo / Gps support and plug-ins to everything I use...plugins

I just finished adding 'Insert GPS Link' support to PockeTwit (a great little Windows Mobile twitter client - really, go and get a copy now...)
Previously I added GeoRSS support to dasBlog for individual blog posts as well as the RSS feed, and I also added geo microformat support to Windows Live Writer with my 'InsertGeoMicroformat' plugin.

So, what's next - have you got an app that needs Geo / GPS support added ?

  PockeTwitIcon   DasBlog Reflection 640x480 Green

GEO 51.4043243116043:-1.28760516643523

Share/Bookmark

Posted: Wednesday, January 21, 2009 9:40:49 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: .NET | ASP.NET | C Sharp | Dasblog | GPS | RSS | Software | Twitter | Windows Mobile

 image I've been toying around with creating an Outlook addin recently that adds a new panel to the main Outlook inspector window. Actually it is going to be a 'folding' or 'collapsing' windows similar to the docked ToolWindows in Visual Studio.image

Anyway, the stuff around getting the correct window handle for the Outlook inspector window and resizing it to allow some space to insert my new panel was fairly simple, but I also had to hook into the message look of the window so that I could capture any move or resize messages and so resize things again to accommodate my panel.

I had started developing it as an Outlook add-in but to speed things up (and prevent me having to register / unregister the addin between tests etc I decided to develop it as a separate app- I could still hook into Outlook and move things around.

The problem came when I was trying to hook the inspector window message loop - it didn't seem to work. I fired up Spy++ and check that the inspector window was getting the messages - which it was - but they were never getting delivered to my hook code.

I was using System.Windows.Form.NativeWindow and overriding the WndProc function (see my NativeWindowListener class below). To get the hook in place I was creating a new NativeWindowListener class with the inspector window handle as the parameter. Checking the handles and the delegates etc it all seemed to be correct, I just couldn't fathom why it wasn't getting any of the messages.

Then the penny dropped. Outlook is in a separate process... (NativeWindow only works across the current process and window handles that are contained in it). What would be needed in this case is a system wide hook, that requires use of the Win32API and interop. I reckon this is overkill just to save a bit of development pain, so will probably move to something where the Outlook addin dynamically loads the panel in and make something available to have the add-in reload the panel - this should allow me to develop the panel code (the majority of the app) without worrying to much about the Outlook addin side of things.

using System;
using System.Windows.Forms;
using System.Text;

namespace Outlook_Subclasser
{
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
internal class NativeWindowListener : NativeWindow
{

    // Constant value was found in the "windows.h" header file.
    private const int WM_SIZE = 0x0005;

    public NativeWindowListener(IntPtr handle)
    {
        AssignHandle(handle);
    }

    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
    protected override void WndProc(ref Message msg)
    {
        switch (msg.Msg)
        {
            case WM_SIZE:
                // do your processing in here
                break;

            default:
                break;
        }
        base.WndProc(ref msg);
    }
}
}

and then to use the class you would find the handle of the window you want to subclass and create a new NativeWindowsListener passing in that handle to the constructor. Note - this does not cover a number of aspects around releasing handles etc - you will want to make sure these are covered off...

MyForm myForm = new MyForm();
NativeWindowListener nwl = new NativeWindowListener(myForm.Handle);

 

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Friday, January 16, 2009 5:06:21 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: .NET | C Sharp | Development | Outlook | Software

I've had a lot of interest in my SMS Gateway app since this post. SMS gateway consist of two components :

SMS Gateway Addinimage
This is an Outlook addin that adds a new toolbar to your Outlook instance. The toolbar allow the user to choose a mobile / cellphone number (from their contacts) and enter a message. When they hit the enter key after the message (or click 'Send') a new Task is created when has a subject of 'SECRETCODE' and the mobile / cellphone number and the details being the text of the message.

At some stage this Outlook Task is synchronized (over ActiveSync / Direct Push) to a Windows mobile device...

SMSGateway
This is a small app running on a Windows Mobile device that every 15 seconds checks through the tasks. If it finds any tasks that have a subject beginning with SECRETCODE then it parses out the mobile / cellphone number and sends the message text (from the Task details) to that mobile / cellphone number via SMS. Note: the SECRETCODE word is configurable.

imageWhy develop this ?
The purpose of this app was really to allow me to send SMS messages easily from Outlook without having to sign up for (and pay for) a web to SMS service (I already get 100's of free SMS messages with my mobile / cellphone package).

The application is free for anyone to use (drop me a line - in the comments - if you do use it...)

Windows Mobile CAB file (copy the file to your Windows Mobile device and click on it) : SMSGatewayMobile.CAB
Setup file for the Outlook 2003 Add-in (Outlook 2007 coming soon) : SMSGatewayAddin2003.msi
Source for both the applications : SMSGateway.zip (includes test Outlook 2007 addin code)

I'd be really interested to hear from anyone using this.... post in the comments...

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Friday, January 09, 2009 10:29:30 PM (GMT Standard Time, UTC+00:00)  #   Comments [5]
TAGS: .NET | C Sharp | Development | Outlook | Software | Windows Mobile

tytnII_101x111_thumbProgrammatically sending an SMS message from your Windows Mobile is fairly simple these days.

You'll need the WM6 SDK. Start a new Visual Studio 'Smart Device Project', add a reference to Microsoft.Windows.PocketOutlook, then use the following code...

using Microsoft.WindowsMobile.PocketOutlook;
..and..
public void Send(string to, string msg)
{
    if ((to != string.Empty) && (msg != string.Empty))
    {
        SmsMessage message = new SmsMessage(to, msg);
        try
        {
            message.Send();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }
}

Job done...

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Monday, October 06, 2008 11:37:41 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | C Sharp | Software | Windows Mobile
 image

Recently I have wanted to be able to send SMS messages to my contacts without having to pick up my phone and mess around with the mini keyboard (I wanted to do it directly from PC, but have the message still send by the phone...

There are solutions around that allow you to send a SMS from a form on a web page, but these are generally paid for services or limited to XX messages per day - I have a mobile contract with unlimited texting, so why would I want to pay for another service, and I didn't want to be limited in the volume of texts I can send per day. there are also solutions around that require the device to be docked / plugged into the PC, I didn't like this either as it's just too much hassle (and therefore I never do it)...

So I came up with a simple but effective solution that makes use of ActiveSync / push email technology that is built into Windows Mobile devices.

Basically I wrote an Outlook Addin that allows me to choose a contact from a drop down list, type in the message and "send" it - when I say "send" it, what I mean is the request is transferred to the WM6 device which then sends the actual SMS message.

image

So it goes like this :-image

  • User chooses the contact from a  drop down list of all contacts with mobile numbers.
  • User enters the text of the message
  • User clicks send
  • Outlook Addin creates a new task with a secret keyword followed by the mobile number as the subject and the message in the body of the task.
  • (after a few seconds) the new task is synchronized to the WM6 device via push email / ActiveSync
  • WM6 device regularly checks the tasks list for a task with a subject that starts with the secret keyword 
  • The subject line is parsed to get the mobile number the text is to be sent to
  • The body is parsed to get the text of the message
  • A SMS message is send from the WM6 device.
  • The new task is deleted (or marked as complete)
  • The change to the task (delete or marked as complete) is synchronized back to the PC via ActiveSync / push email.

I'll have more details, the installers and all the source code available next week...

 

UPDATE: See the follow up to this article here which includes binary files and full source code.

 

GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Thursday, October 02, 2008 10:40:26 PM (GMT Daylight Time, UTC+01:00)  #   Comments [5]
TAGS: .NET | C Sharp | Development | Outlook | Windows Mobile

imageOriginally I had my website set up to default to my blog (so dasBlog was installed at the website root level instead of in a /blog subfolder).

Recently I have been writing some Web Applications and wanted to restructure my website so that there is a subfolder for each app / main area (blog, projects, etc).

The problem being that all the links out there point to http://www.kapie.com/2007/12/19/RedirectorHttpModule.aspx and these would all be dead link when moved to http://www.kapie.com/blog/2007/12/19/RedirectorHttpModule.aspx, so I needed to respond with a HTTP 302 to the original links and tell the client that it should temporarily redirect to the new location (changing to a HTTP 301 when I am happy that it is all working).

This called for a HttpModule...

namespace KSL
{
public class BlogRedirector : IHttpModule
{
VisualStudioLogo private EventHandler onBeginRequest;

public BlogRedirector()
{
onBeginRequest = new EventHandler(this.HandleBeginRequest);
}

void IHttpModule.Dispose()
{
}

void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += onBeginRequest;
}

private void HandleBeginRequest( object sender, EventArgs evargs )
{
HttpApplication app = sender as HttpApplication;

if ( app != null )
{
HttpContext context = app.Context;
string host = app.Request.Url.Host;
string requestUrl = app.Request.Url.PathAndQuery;

if (requestUrl.Contains(@"/blog/")
|| requestUrl.Contains(@"/foo1/")
|| requestUrl.Contains(@"/foo2/")
|| requestUrl.Contains(@"/foo3/")
|| requestUrl.Contains(@"/foo4/")
|| (requestUrl.ToLower() == app.Request.Url.Scheme + @"://" + host + @"/default.aspx"))
{
return;
}
else
{
Uri newURL = new Uri(app.Request.Url.Scheme + @"://" + host + @"/blog" + requestUrl);
context.Response.RedirectLocation = newURL.ToString();
context.Response.StatusCode = 302;
context.Response.End();
return;
}
}
}
}
}

This basically allows me to redirect any url that does not contain /blog/ or /foo*/ or is not /default.aspx by sending a 302 status code and adding /blog/ to the url to generate the redirect url. The compiled DLLs were stored in the bin folder off the root and the web.config in the root needed the following adding...

<?xml version="1.0" encoding="UTF-8"?>
<
configuration>
<
system.web>
<
httpModules>
<
add type="KSL.BlogRedirector,BlogRedirector" name="BlogRedirector" />
</
httpModules>
</
system.web>
</
configuration>

This seemed to work fine some of the time, but was a bit hit and miss.... Further investigation pointed me at the web.config files in the subfolders and that they would inherit the sections from the root web.config. So all the subfolder web.config files got the following added.

<?xml version="1.0" encoding="UTF-8"?>
<
configuration>
<
system.web>
<
httpModules>
<
remove name="BlogRedirector" />
</
httpModules>
</
system.web>
</
configuration>
GEO 51.4043197631836:-1.28760504722595

Share/Bookmark

Posted: Wednesday, December 19, 2007 7:09:38 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: .NET | ASP.NET | C Sharp | Development | Web

InsertPanel I have just completed a new Windows Live Writer plugin. This extension allows ease insertion of geo microformat information.

It allows the user to easily choose the location they want to insert (in microformat) from a Virtual Earth map and also configure how it is displayed (if at all on the post.

Recently I (with considerable help from Alexander Groß) added GeoRss support for dasBlog. The co-ordinates can be specified when adding a post via the web interface. This plugin is stage two of this support, stage three will be parsing the geo microformat when a post is added and using that to populate the GeoRss info.

The end goal being to allow the geo info to be entered when creating a post in Writer and having that info available in GeoRss format in the feed.

I started this plugin with the view to using Google Maps, however they require that you get an API key and that key is only valid for a particular web site / URL path. This foiled my plans to embed the map in a Windows Forms WebBrowser control (I did look at producing an html page that was served from my web site, and using it embedded in the WebBrowser - not scaleable and too much configuration for a normal user to do.

InsertMicroformat 

I hadn't looked in depth at Virtual Earth, but recently went to MixUK:07 and saw a couple of demos / presentations on it - a quick look found that it didn't need a API and was not tied to a particular URL / path - the JavaScript for it is pretty similar to the one for Google Maps so learning curve was pretty short. The only issue I have with http://local.live.com is that there is no (currently) facility to enter a GeoRss feed in the search query and just display the data (the current method of displaying this kind of data is to embed a map in your own pages and use their API to display the items as a 'collection').

You can get the installer for it here InsertGeoFormatSetup.msi (325Kb).

GEO 51.4043243116043:-1.28760516643523

Share/Bookmark

Posted: Saturday, September 15, 2007 11:12:11 PM (GMT Daylight Time, UTC+01:00)  #   Comments [5]
TAGS: .NET | ASP.NET | C Sharp | Dasblog | GPS | RSS | Web

I have completed stage one of GeoRss enabling dasBlog.

In the config page I added some options for enabling GeoRss, specifying a default lat/long and enabling ‘integration’ with Google maps. There is also an option to use the default lat/long for any non geocoded posts.

  clip_image0022_thumb1

If GeoRss is enabled then the edit entry screen provides textboxes to allow specifying lat/long (populated with defaults from config page).

clip_image00421_thumb2

If the google maps integration is enabled then you’ll get the ‘Show Map’ button and clicking it will display a map which you can move around until you find the location and then click on the location to get the lat/long texboxes populated.

clip_image00681_thumb1

If you have existing non geocoded posts then you can have the default lat/long added to those if you wish.

I puzzled around for ages when trying to display the georss in google (http://maps.google.com/maps?q=yourfeedaddress) – it kept telling me that the feed was invalid. I eventually found that feedburner was adding <atom10:link blah blah /> to the xml which for some reason google maps thinks is invalid. The only way I could find to prevent feedburner adding the atom link was to turn OFF the ‘Browser Friendly’ feature in feedburner.

So – stage 2...

The work I still want to do with this is basically to add macros to get lat/long  - fairly easy I guess, and then some way to specify lat/long from Windows Live Writer (and other offline blog clients) – a little more complex. Scott mentioned a geo microformat and from my initial looks seems to be a good route to take - watch this space...  

Now it is simply a case of retrofitting the geo info into all my old posts...

 

Share/Bookmark

Posted: Saturday, September 08, 2007 10:33:40 PM (GMT Daylight Time, UTC+01:00)  #   Comments [1]
TAGS: .NET | ASP.NET | C Sharp | Dasblog | Development | GPS | RSS | Software

Some of the code I have for importing data (from ACT! 2000) to MS CRM creates new 'PhoneCall' activities / objects. The problem is, that it seems MSCRM does not allow you to programmatically modify the 'create date'.

Here is the code I use...

phonecall pc

            CrmDateTime start = new CrmDateTime();

            start.Value = DateTime.Parse("10/08/2005 12:30");

            pc.actualstart = start;

            pc.scheduledstart = start;

            CrmDateTime end = new CrmDateTime();

            end.Value = DateTime.Parse("10/08/2005 14:30");

            pc.actualend = end;

            pc.scheduledend = end;

            pc.subject = "Phone call regarding sales of Widgets Q2/2005");
***

            string desc =  "Start    : " + pc.actualstart.Value + "\n";

            desc += "End       : " + pc.actualstart.Value + "\n\n";
***

            desc += "The details of the phone call go in here");

            pc.description = desc;

            pc.regardingobjectid = new Lookup();

            pc.regardingobjectid.type = EntityName.contact.ToString();

            Guid contactGuid = new Guid(guidOfContactWeTelephoned);

            pc.regardingobjectid.Value = contactGuid;

 

 

The actualstart and scheduledstart (and ends) get populated with the current datetime (this seems to happen if the time they are set to is in the past).

 

Note the two lines between the ***'s - this is my solution / workaround and simply include the start/end times as text in the body/description of the phone call object.

 

Share/Bookmark

Posted: Monday, August 20, 2007 2:07:39 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | C Sharp | Development | MSCRM | Software

dasBlog_image So dasBlog 2.0 (running under AS.NET 2.0 and medium trust) is now released. Scott has a great write up on it.

I have been running this web site on it for a few weeks now and it's been fine. We sneaked in a couple of last minute features (one of mine was a new macro for rendering the navigation links as an Unordered List instead of a table with one cell per row).

I've been spending a fair bit of time on dasBlog recently - extending activity Rss feed and working on georss integration. I have a georss version working with a simple UI allowing the user to specify Lat/Long for each post and then a link to view the feed items in Google maps. I have not checked it in yet as I want to provide a slicker UI for specifying the location (maybe a map that allows you to drag/select the location or enter a zip code and view the location then use that).
I also want to provide options for getting the location in when using blogging clients (Windows Live Writer etc), not just the web based 'add entry' UI.

There is also some great work going on with Clemens Vaster and other really revamping some of the architecture bits and bringing dasBlog to the next level.

Watch this space...

Share/Bookmark

Posted: Thursday, August 16, 2007 2:30:55 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | ASP.NET | Dasblog | Development

A few months ago I added a 'Daily Report Email' feature to dasBlog, so I could have the activity reports (referrers, searches etc) delivered to my mailbox at the end of every day.
I wanted to take this one step further and deliver it via RSS (and dasBlog is a RSS engine after all).

There were a couple of suggested methods raised on the dasBlog developers mailing list; one was using HTTP authentication - I was reluctant to use this as Outlook 2007 does not support authorized feeds. The other suggestion was to obfuscate the URL with a Guid or the like - this was my preferred option.

So, I have been working on it over the past few evenings, got it rolled out to this blog and it seems to be working pretty well.

image

I added a checkbox to the site configuration page, that when checked generates a Guid that is used as part of the path. The 'activityrss.ashx' page doesn't exist at that path (in fact it doesn't exist at all!), instead there is a HttpHandler for the file 'activityrss.ashx' that intercepts any requests for that file and does some processing.

In this processing I check that the requested URL contains the Guid and if so, generate the Activity RSS feed. The content of each feed item is the activity report (similar format to the daily report email).

image

NOTE: This is not in a release yet, if you want it you'll have to check out the source, patch it with this patch file and compile, deploy it manually.

 

Share/Bookmark

Posted: Saturday, July 21, 2007 12:18:41 AM (GMT Daylight Time, UTC+01:00)  #   Comments [1]
TAGS: .NET | ASP.NET | C Sharp | Dasblog

So after some poor experiences with the MSCRM Data Migration framework I decided to get pragmatic and write a C# app to do the migration.

The CDF is poorly documented at best, it seems they (Microsoft) give you a bunch of database tables, an Excel spreadsheet outlining the schema and a 'Good Luck'. There is little 'googleable' (is that a word) knowledge about it either.

The good news was that the MSCRM SDK is much better documented (on MSDN). There is not a lot of googleable info around but there is enough (Stunnware proved pretty helpful for me).

There were other challenges also - the software we purchased for exporting the ACT! 2000 data to Access (Exporter Pro) did a good job of getting the data out of ACT but the Unique ID left a bit to be desired, they are basically a munge of punctuation characters and alphanumerics - what's wrong with a GUID or a int ??

So, anyway, I got there in the end...

The connecting to the CrmService was pretty easy, as was the population and addition of an account.

            crmSvc = new CrmService();

            crmSvc.Url = MsCrmUrl;

            crmSvc.Credentials = new System.Net.NetworkCredential(CrmUsername, CrmPassword, CrmDomain);

 

            account acct = new account();

            acct.name = "company name";

            acct.address1_line1 = "address line one";

            acct.address1_line2 = "address line two";

            acct.address1_line3 = "address line three";

            // etc

 

            Guid acctGuid = crmSvc.Create(acctGuid);

 

 

Simple as that - do it for each account...

Next installment will outline adding Contacts an then linking them to an account.

 

Share/Bookmark

Posted: Tuesday, July 03, 2007 9:51:25 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | C Sharp | MSCRM | Software

I'm in Western Mass (Westboro, MA) again this week and while that normally means 16 hour days (there is nothing much else to do but sit around a hotel room so why not...), this week I decided to work on a personal project for a bit.

Part of it was some code to check a machines public IP address and update it to DynDNS. Luckily they have an excellent developers / API section that explains everything you need to do this. There are two sections to it, detecting the machines public IP address and updating the hostnames associated with your account, both of which they provide a service for.

It's pretty easy to follow and within an hour or so I had come up with a class to do both tasks. Here is a snippet for the 'CheckIP' function:

public static string CheckIP()

{

 

    // check the current public IP address

    string ipString = string.Empty;

    WebClient wc = new WebClient();

    try

    {

        string result = wc.DownloadString("http://checkip.dyndns.com");

        return ParseCheckResult(result);

    }

    catch (WebException)

    {

        ipString = string.Empty;

    }

    return ipString;

}

 

 

Just call a URL (http://checkip.dyndns.com) and it returns your public IP address, there was some parsing of the return text but it is pretty simple. Click the link and see for yourself.

 

Next was the 'UpdateIP' function, here's the snippet:

public static string UpdateIP(string username, string password, string ipaddr, string hosts)

{

    // check the current public IP address against what we want to update to

    string updateurl = "http://members.dyndns.org/nic/update?hostname";

    string result = string.Empty;

    WebClient wc = new WebClient();

 

    string url = string.Format(@"{0}={1}&myip={2}&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG", updateurl, hosts, ipaddr);

    try

    {

        wc.Credentials = new NetworkCredential(username, password);

        wc.Headers.Add("User-Agent", "KSL - WHS Updater - 1.0");

 

It is basically just a case of passing a querystring with all the details to http://members.dyndns.org/nic/update , ensuring you set the credentials to your DynDNS account username and password and specifying a unique User-Agent.

 

The complete project files (including a small 'user' application to test it) can be found here (61K).

Share/Bookmark

Posted: Tuesday, June 19, 2007 2:27:49 AM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | C Sharp | Development | Software | Tools

Just didn't work for me.

I had it all set up as per the docs, imported the data into the CDF database, tried to 'Migrate' and it completed but migrated no records (even though I had 8000+ in the CDF tables).

I tried both the snippets I gleaned from googling :

  • Make user the user does not have 'Restricted Access'
  • Turn off 'Fast Load' mode.

Still no joy. All the 'required' fields are populated, the mapping wizard works correctly, but no 'migration'. It is a real pain as there is nowhere to go next, the documentation about CDF is really poor as is the logging/trace/error output from the Migration Wizard.

Ever the pragmatist, I cracked open VS and and have started on an app which uses the CrmService webservice to import the data. Watch this space for the source when I'm done...

Share/Bookmark

Posted: Friday, June 01, 2007 1:34:41 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | C Sharp | Software

 I use dasBlog as the vehicle/technology for this site and currently have it configured at the root of the website (so you go to http://www.kapie.com/blog and you get directly into this blog). This is kind of an unusual setup as most people put it in a /blog subdirectory or virtual directory.

I have plans to put a fair bit more static content up so I wanted to change to the standard of /blog subfolder - the problem is that all my current links will fail when I move the content along with all the content google has cached / indexed about the site - Not Good.

Scott Hanselman suggested in response to a question I posed on the dasBlog mailing list that writing a HttpModule with a HTTP temporary redirect (HTTP response code 302) might be the way to go and reckoned it might only be a handful of lines of code....

 I was pleasantly surprised at how easy it was...

I have included the code below in case anyone else might find it useful. It is pretty specific at the moment (takes the requested URL and if it does not include /blog/ then it insert it) but it could easily by made generic (RegEx or the like).

Happy to share the actual source files if anyone wants them - drop me a mail/comment. 

using System;

using System.Web;

using System.Text;

 

 

namespace KH

{

    public class Redirector : IHttpModule

    {

        private EventHandler onBeginRequest;

 

        public Redirector()

        {

            onBeginRequest = new EventHandler(this.HandleBeginRequest);

        }

 

        void IHttpModule.Dispose() { }

 

        void IHttpModule.Init(HttpApplication context)

        {

            context.BeginRequest += onBeginRequest;

        }

 

        private void HandleBeginRequest(object sender, EventArgs evargs)

        {

            HttpApplication app = sender as HttpApplication;

 

            if (app != null)

            {

                string host = app.Request.Url.Host;

                string requestUrl = app.Request.Url.PathAndQuery;

                if (requestUrl.IndexOf("/blog/") == -1)

                {

                    Uri newURL = new Uri(app.Request.Url.Scheme + "://www." + host + "/blog" + requestUrl);

                    app.Context.Response.RedirectLocation = newURL.ToString();

                    app.Context.Response.StatusCode = 302;

                    app.Context.Response.End();

                    return;

                }

                else

                {

                    return;

                }

            }

        }

    }

}

 

 

Share/Bookmark

Posted: Thursday, March 08, 2007 8:10:19 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: .NET | C Sharp | Dasblog | Development

We had a customer issue yesterday that manifested itself as the user getting a HTTP 401 error when trying to connect to a Website (that is part of our Product).

The user was logged into the domain, the virtual directory was set for 'Windows Integrated Authentication' so they should have been able to connect no problem.

After so investigation we opened the IIS logs and found that the substatus code was 2 (HTTP Error 401.2 - Access denied by server configuration). A bit of searching around the Microsoft KB unearthed this article:

Troubleshooting HTTP 401 errors in IIS

Common reasons

• No authentication protocol (including anonymous) is selected in IIS. At least one authentication type must be selected. For more information, click the following article number to view the article in the Microsoft Knowledge Base:

253667 (http://support.microsoft.com/kb/253667/) Error message: HTTP 401.2 - Unauthorized: Logon failed due to server configuration with no authentication

• Only Integrated authentication is enabled, and an older, non-Internet Explorer client browser tries to access the site. This happens because the client browser cannot perform Integrated authentication. To resolve this problem, use one of the following methods:

• Configure IIS to accept Basic authentication. This should only occur over SSL for security purposes.

• Use a client browser that can perform Integrated authentication. Internet Explorer and new versions of Netscape Navigator and Mozilla Firefox can perform Integrated authentication.

• Integrated authentication is through a proxy. This happens because the proxy doesn't maintain the NTLM-authenticated connection and thus sends an anonymous request from the client to the server. Options to resolve this problem are as follows:

 

• Configure IIS to accept Basic authentication. This should only occur over SSL for security purposes.

• Don't use a proxy.

 

Turns out our customer was using a Proxy Server - adding the FQDN of our Website component to the proxy exclusions list solved the problem.

Share/Bookmark

Posted: Wednesday, January 03, 2007 10:32:46 PM (GMT Standard Time, UTC+00:00)  #   Comments [1]
TAGS: .NET | Archiving | Software | Support

At work I have been the champion of an Integration Framework for our Archive One product. This is a set of API's, events and open file formats embedded into the Archive One products that allow customization 'around the edge'.

The kind of thing that can be done with the Integration Framework is running searches, interworking with the AD schema, running archive policies, integration into Network Management Systems or Document Management Systems and the like - it really opens the product to other business systems as either the slave (other systems controlling Archive One) or the master (other systems being controlled by Archive One).

We have been writing up the API documentation recently and had initially started this as a (Word) document we would publish to customers and developers. I looked into NDoc which now seems dead (at least for VS2005 and .NET2.0) and then came across Sandcastle. Sandcastle is Microsoft's answer to NDoc, it allows the collation and generation of documentation from the XML comments embedded in your code

Right now it is at CTP stage and is command line driven - a few projects have sprung up which provide a UI for it (backing on to the CLI). One is a VS2005 add in (which I installed but it wasn't immediately obvious how to use it, so I didn't really pursue) and other is SandcastleGUI - this provides a single form where you choose the options, point it to the folders containing the Sandcastle app, the code DLLs and where you want the docs to end up and then simply kick it off.

When you hit 'Start Documenting' it closes the form and fires off a command prompt window (batch files) which in turn fires off other command prompt windows until it's collated everything and built the documentation.

It allows you to generate html documents - a whole website, multiple pages, images etc or a compiled help file (.chm) or even both if you wish.

Another of the options is 'Online MSDN Links' this provides a MSDN link for every object type it can find in the base class library. Be warned enabling this option means it has to reflect through about 14500 classes / objects in the framework so that they can be indexed and used if found in your app / library. Enabling this option increases the time to generate from about 1 minute (on my Dual Core laptop) to about 15 minutes - I'd recommend disabling this option whilst developing the app / library and only enable it when you are doing the final or release build.

The resulting documentation is really good quality - pretty much the same format as MSDN documentation.

For the effort of a few extra XML comment lines in your code this provides great value and a very comprehensive resulting document.

The easiest way I have found to integrate this into VS2005 is to set it up as an External Tool.

I create a folder under the solution folder named 'Documentation', I run SandcastleGUI manually the first time around, do all the required configuration and then save the settings to a file in the solution directory (don't save it in the 'Documentation' folder as that is cleared out with each Sandcastle run.

I have an 'External Tool' configured which points to SandcastleGUI with parameters of :

/document $(ProjectDir)\settings.SandcastleGUI

(I called the settings file 'settings.SandcastleGUI') and called the tool :

Sandcastle This Project

This allows me to simply click this tool and it will go away and create all the documentation (with my chosen parameters) for the project.

As I mentioned this is CTP at the moment - I look forward to the release version, hopefully fully integrated into Visual Studio and stylesheets that exactly mimic MSDN.

Share/Bookmark

Posted: Wednesday, November 22, 2006 9:27:47 PM (GMT Standard Time, UTC+00:00)  #   Comments [1]
TAGS: .NET | Archiving | Development | Software | Tools

In the first version of my GPS Library software (written in VB6) I had a 'Protocol' property that indicated which protocol we were using (for example Garmin, Magellan, NMEA etc). Then, every time we needed to do something at the protocol layer (Sending or Receiving data) we had an if statement :

If gps.Protocol = GpsProtocol.Garmin Then
     ' Do it this way
EsleIf gps.Protocol = GpsProtocol.Magellan Then
     ' Do it that way
Else
     ' Do it the other way

Horrible and messy !! Adding a new protocol meant going back to every function and amending it.

In the new .NET version, it's much more object oriented and I've used a number of software design patterns.

To solve the above problem I used a Factory pattern. The Factory pattern allows you to create objects but let the client decide what type those objects should be. So, I can basically let the client set the Protocol property and then, depending on that setting create a different object for each protocol.

I start with a base class that all the 'codec' classes inherit from, then in the 'creation' (when the client creates the object) I look at the Protocol property and choose which concrete class to return:

GpsCodec is the base class and the concrete classes are GarminCodec, MagellanCodec etc. I have a static method in the base class called 'CreateCodec' that takes a 'Protocol' parameter. So it looks like this

public static GpsCodec CreateCodec(GpsProtocol protocol)
{
     switch (protocol)
     {
          case GpsProtocol.Garmin:
               return new GarminCodec();
               break;
          case GpsProtocol.Magellan:
               return new MagellanCodec();
               break;
          default:
               return null; // error
               break;
     }
}

So now I can simply create a codec class based on the Protocol property and use that for all the communication to / from the device. Adding a new protocol is simply a case of creating the new class and modifying the CreateCodec method - much simpler.

Watch this space for the free .NET GPS Library (including source).

Share/Bookmark

Posted: Sunday, November 12, 2006 3:57:31 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: .NET | C Sharp | Design Patterns | Development | GPS

In the first version of my GPS Library (written in VB6) I had a big horrible multiple nested if statement that handled the intelligence behind what to do when a new frame of data was received - if we were sending Waypoints to the GPS and the frame was an Acknowledgement (ACK) then we would send the next one, if it was a Not Acknowledgement (NACK) then we'd retransmit the last one - everything that happened depending on the current context (what we are currently doing). As there were about 20 different things we could be doing at the time and about 20 odd frame types, this was real messy and probably had a Cyclometric Complexity of 9292736592 (or more)...

My .NET version of the GPS Library makes extensive use of Software Design Patterns - to solve the problem above I used a 'State' pattern.

The State pattern is used where your software has multiple states and various actions or stimulations that make it change between states (but it is always going to be in one of the predefined states). I guess it a pretty common pattern for communication systems.

I have a base class called GpsState, that contains all an (overrideable) method for each action and stimulation and each method has a default implementation of something like

throw new Exception("Invalid action for state :" + this.StateName);

All the state classes inherit from this base state class.

Lets take (much simplified) sending Waypoints as the example:-

The GPS object has a reference to the current state class. This starts off in the stateIdle (doing nothing). We then call the stateIdle.WriteWaypoints() function. In this function we send the first Waypoint and change the state to stateWritingWaypoints.
The stateWritingWaypoints overrides the 'GotACK' method and provides it own implementation (which is simply to send the next Waypoint). If any of the other methods are called whilst in the stateWritingWaypoints then the implementation from the base class is called and the caller receives an exception.
When I've sent the last Waypoint then I change state back to stateIdle so that other actions can be called again

So my class for stateWritingWaypoints handles writing Waypoints and nothing else - this makes the code really clean and simple. The downside is that you end up with many more (small) classes in your code.

Watch this space for the source to the free .NET GPS Library.

Share/Bookmark

Posted: Sunday, November 12, 2006 3:26:18 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: .NET | Design Patterns | Development | GPS

About 4 or 5 years ago I wrote a GPS ActiveX control in VB6.0.
Although it work really well (and fast), it was difficult to maintain - to be honest it was pretty messy, a large monolith with some real horrible 283654276354 line functions.
I sold it as Kapie Systems for a while and had some good success with it, it was mentioned at a couple of GIS conferences etc...

Anyway, I had been meaning to update it (to .NET) for sometime, but I wanted to do it right, make it easy to extend (to plug-in other GPS protocols) and easy to maintain.

I just got a basic .NET implementation of it working last night (at last !!). It's Garmin propriety protocol only at the moment, but the whole framework is there for extending to other protocols (which I'll be adding shortly).
I also added import and export to GPX format, which is a great portable standard - the GIS / Mapping community has been crying out for this for ages.

I expect to have something releasable in a few weeks (it will be open source) but if anyone wants an early view or wants to discuss my plans ideas then let me know.

Share/Bookmark

Posted: Friday, November 10, 2006 12:00:33 AM (GMT Standard Time, UTC+00:00)  #   Comments [3]
TAGS: .NET | C Sharp | Development | GPS

One of my gripes with dasBlog is the reporting. To get to reports I have to browse to my blog, login and then view the reports online - bit of a pain doing this every day (yes I am so vain that I like to see my stats on a daily basis).

So I spent a few hours recently adding an 'Daily Activity Report' feature.  It was surprising easy - checkout (get a working copy) of the source from sourceforge (browse it here https://svn.sourceforge.net:443/svnroot/dasblogce/trunk), familiarize yourself with it, add your changes and create a patch. Send the patch to someone with admin rights (so it can be checked in) and that's it... I'd recommend to anyone to try it out...

Anyway the 'Daily Activity Report' feature - basically starts a background thread which caches the current date and then ticks every hour. Each tick it will check the current date against the cached date and if they do not match then it will send an email to either the Notification list or the Site Owner / Administrator. It is configured by simply checking a box in the configuration page (in the SMTP Server section)

The email contains similar detail to that of the 'Activity... Referrers' page.

I also made the method / class that implements the creating / sending the report public so that it can be extended - I was thinking along the lines of a 'Send Daily Activity Report Now' button or enhancing the Mail-To-Weblog to monitor for a specific phrase in the subject and if found to send the report (maybe also specify the date)...

Watch this space for updates...

Share/Bookmark

Posted: Wednesday, November 08, 2006 3:02:13 PM (GMT Standard Time, UTC+00:00)  #   Comments [1]
TAGS: .NET | C Sharp | Dasblog | Software

Singleton Design Pattern, is a solution to a common problem in the software domain where you want to create ONE AND ONLY ONE instance of an object/class.

Put simply, it stops client applications creating their own instances of an object and routes all creation of the object through one method. If an instance of the class already exists then that instance is returned, if an instance of the class does not exist then a new instance is created.

So, no matter how many clients access the class there is only ever one instance (that all clients access)

Here's some sample code of how to achieve a Singleton class :

using System;

using System.Collections.Generic;

using System.Text;

 

namespace KenAndSarah.GpsControl

{

    public class GpsControl

    {

        private static GpsControl instance = null;

 

        private GpsControl()

        {

            // do not allow a public constructor

        }

 

        // call this to get (or create) a reference to the class

        public static GpsControl GetGpsControl()

        {

            if (instance == null)

                instance = new GpsControl();

            return instance;

        }

    }

}

 

So to clients would simply use it like this

        GpsControl gps = GpsControl.GetGpsControl();

 

Any subsequent clients who make the same call get a reference to the already created instance of the class.

Share/Bookmark

Posted: Friday, October 06, 2006 3:50:20 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | C Sharp | Design Patterns | Development | Software

Here's the code for the macros I created - feel free to copy / compile it yourself. I also included a compiled DLL here - BUT it is compiled against .NET2.0 so will only work if your hosting Dasblog in a ASP.NET2.0 virtual directory.

  • Copy the compiled DLL into your /bin folder
  • Edit your Web.config file, locate the <newtelligence.DasBlog.Macros> node
  • Add the following element <add macro="khmacros" type="KensDasblogMacros.KensMacros, KensMacros"/>
  • Edit your template pages to include <%TrackbackCount()|khmacros%> or <%TrackbackountAll()|khmacros%> or <%KensBlogStats()|khmacros%>

using System;

using System.Collections;

using System.Text;

using System.Web.UI;

using newtelligence.DasBlog.Runtime;

using newtelligence.DasBlog.Web.Core;

using newtelligence.DasBlog.Util;

 

 

namespace KensDasblogMacros

{

    public class KensMacros

    {

 

        protected SharedBasePage sharedBasePage;

        protected Entry currentEntry;

 

        public KensMacros(SharedBasePage page, Entry entry)

        {

            sharedBasePage = page;

            currentEntry = entry;

        }

 

        public virtual Control TrackbackCount()

        {

            if (this.currentEntry != null)

            {

                int trackbackCount = 0;

                IBlogDataService dataService = sharedBasePage.DataService;

                trackbackCount = dataService.GetTrackingsFor(currentEntry.EntryId).Count;

                return new LiteralControl(trackbackCount.ToString());

            }

            return new LiteralControl("");

        }

 

        public virtual Control TrackbackCountAll()

        {

            int trackbackCountAll = 0;

 

            IBlogDataService dataService = sharedBasePage.DataService;

            DateTime[] daysWithEntries = dataService.GetDaysWithEntries(UTCTimeZone.CurrentTimeZone);

 

            foreach (DateTime day in daysWithEntries)

            {

                EntryCollection entries = dataService.GetEntriesForDay(day, UTCTimeZone.CurrentTimeZone, String.Empty, 1, int.MaxValue, String.Empty);

                foreach (Entry potentialEntry in entries)

                {

                    trackbackCountAll += dataService.GetTrackingsFor(potentialEntry.EntryId).Count;

                }

                return new LiteralControl(trackbackCountAll.ToString());

            }

            return new LiteralControl("");

        }

 

        public virtual Control KensBlogStats()

        {

            StringBuilder sb = new StringBuilder();

 

            try

            {

                IBlogDataService dataService = sharedBasePage.DataService;

 

                DateTime monthFirst = new DateTime((DateTime.UtcNow.Year), (DateTime.UtcNow.Month), 1, 0, 0, 0);

                DateTime monthLast = new DateTime((DateTime.UtcNow.Year), (DateTime.UtcNow.Month), DateTime.DaysInMonth(DateTime.UtcNow.Year,DateTime.UtcNow.Month),23,59,59);

 

                DateTime weekFirst = Macros.GetStartOfCurrentWeek();

                DateTime weekLast = Macros.GetEndOfCurrentWeek();

 

                DateTime yearFirst = Macros.GetStartOfYear(DateTime.UtcNow.Year);

                DateTime yearLast = Macros.GetEndOfYear(DateTime.UtcNow.Year);

 

                int allEntriesCount = 0;

                int yearPostCount = 0;

                int weekPostCount = 0;

                int monthPostCount = 0;

                int trackbackCount = 0;

                DateTime[] daysWithEntries = dataService.GetDaysWithEntries(newtelligence.DasBlog.Util.UTCTimeZone.CurrentTimeZone);

                foreach (DateTime day in daysWithEntries)

                {

                    EntryCollection entries = dataService.GetEntriesForDay(day, newtelligence.DasBlog.Util.UTCTimeZone.CurrentTimeZone, String.Empty, 1, int.MaxValue, String.Empty);

                    allEntriesCount += entries.Count;

                    foreach (Entry potentialEntry in entries)

                    {

                        if (potentialEntry.CreatedUtc > monthFirst && potentialEntry.CreatedUtc <= monthLast)

                        {

                            monthPostCount++;

                        }

 

                        if (potentialEntry.CreatedUtc > weekFirst && potentialEntry.CreatedUtc <= weekLast)

                        {

                            weekPostCount++;

                        }

 

                        if (potentialEntry.CreatedUtc > yearFirst && potentialEntry.CreatedUtc <= yearLast)

                        {

                            yearPostCount++;

                        }

 

                        trackbackCount += dataService.GetTrackingsFor(potentialEntry.EntryId).Count;

                    }

                }

 

                int commentCount = dataService.GetAllComments().Count;

 

                sb.Append("<div class=\"blogStats\">");

                sb.Append("<table border=\"0\" width=\"100%\">");

                sb.Append("<tr><td align=\"left\">Total Posts</td><td align=\"right\">" + allEntriesCount + "</td></tr>");

                sb.Append("<tr><td align=\"left\">This Year</td><td align=\"right\">" + yearPostCount + "</tr></td>");

                sb.Append("<tr><td align=\"left\">This Month</td><td align=\"right\">" + monthPostCount + "</tr></td>");

                sb.Append("<tr><td align=\"left\">This Week</td><td align=\"right\">" + weekPostCount + "</tr></td>");

                sb.Append("<tr><td align=\"left\">Comments</td><td align=\"right\">" + commentCount + "</tr></td>");

                sb.Append("<tr><td align=\"left\">Trackbacks</td><td align=\"right\">" + trackbackCount + "</tr></td>");

                sb.Append("</table>");

                sb.Append("</div>");

            }

            catch (Exception ex)

            {

                sharedBasePage.LoggingService.AddEvent(new EventDataItem(EventCodes.Error, "KensBlogStats Error: " + ex.ToString(), String.Empty));

            }

            return new LiteralControl(sb.ToString());

        }

 

    }

 

 

}

Share/Bookmark

Posted: Tuesday, October 03, 2006 11:04:24 PM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | C Sharp | Dasblog | Software

So, having recently updated this website to Dasblog 1.9, I decided it was time to check out the source and have a play around.

The initial easy step to get involved seemed to be writing some Macros (I wanted to extend the default blogStats() macro to include Total Trackbacks and also add a Trackback Count to each post item in the footer.

There is a great intro to Creating Dasblog Macros on their Documentation Site, also googling for Dasblog macros uncovered a few good sites

Anyway, I cracked open VS and spent a couple of hours writing some new macros, compiled them, made the requisite changes to my homeTemplate and itemTemplate but they just seemed to be return null strings. Checking the (Dasblog) event log showed that it was failing the find the Type for my Macros.

I checked and rechecked everything and was convinced that everything was as it should be. Stumped!!
Viewed my DLL in reflector, typenames were all correct - what was I doing wrong ??

A quick post to the Dasblog developers mailing list resulted in someone suggesting that I check if I was running a .NET2 compiled DLL in a .Net1.1 IIS virtual directory - Doh !!

Updated the virtual directory to ASP.NET 2.0 (easier than reverting to VS2003 from VS2005), 'touched' the web.config, refreshed the page and 'ta da...'

Changes and source code to be rolled out to this web site in the next day or so (more testing to do on how ASP.NET 2.0 works out),

Share/Bookmark

Posted: Tuesday, October 03, 2006 3:26:44 AM (GMT Daylight Time, UTC+01:00)  #   Comments [0]
TAGS: .NET | C Sharp | Dasblog | Development | Software

Quick update on the TaHoGen open source project...

I just tidied up the whole source tree, added all the projects in a logical layout to one solution. I also sorted out the Visual Studio addin with better error handling and added a Setup project so that it can be easily installed by an end user.

Murad's excellent SchemaBrowser was added added and checked in, now allowing us to glean data from databases to use in the code generation. We're closing in on CodeSmith...

Next step is to demonstrate use by including a number of templates.


The problem with the addin (that was so difficult to remedy) was MDA's - difficult to troubleshoot and even more difficult to fix.

When the addin is called by VS it tries to save a reference to the instance of VS that is creating it - this is so we can get a handle on the OutputWindow and add some new panes to it.

These sometimes (intermittently) get blocked by MDA's and the panes do not get created - the panes only show build output text so I added some error handling to continue processing even if we cannot write to the pane.

Anyway, if you want to take it for a test run, you can get it here.

Share/Bookmark

Posted: Thursday, September 28, 2006 10:49:02 PM (GMT Daylight Time, UTC+01:00)  #   Comments [7]
TAGS: .NET | C Sharp | Code Generation | Development | Software | TaHoGen

Blank entry, simply to list out the categories.

Share/Bookmark

Posted: Saturday, January 01, 2005 5:32:53 PM (GMT Standard Time, UTC+00:00)  #   Comments [0]
TAGS: Archiving | C Sharp | Code Generation | Exchange | Family | Mountaineering | PHP | RSS | Scripting | Support | Technical | .NET | Design Patterns | Hardware | Dasblog | Running | Tools | Development | Software | TaHoGen | GPS
     
 
 
Copyright © 2010 Ken Hughes. All rights reserved.

Creative Commons License
This work is licensed under a Creative Commons Attribution 2.0 UK: England & Wales License.