FluentHtmlTextWriter

[Source: http://geekswithblogs.net/EltonStoneman]

Keeping up the fluent work, I’ve put together a fluent interface which wraps the framework HtmlTextWriter. For ASP.NET MVC, this makes generating HTML in extension methods to HtmlHelper safer than string.Format() and more readable than HtmlTextWriter:

public static string Image(this HtmlHelper helper, string imageRelativeUrl, string altText)

{

return FluentHtmlTextWriter.Begin()

.WriteTag(HtmlTextWriterTag.Img)

.WithAttribute(HtmlTextWriterAttribute.Src, GetImageUrl(imageRelativeUrl))

.WithAttribute(HtmlTextWriterAttribute.Alt, altText)

.End();

}

The equivalent using HtmlTextWriter is:

public static string Image(this HtmlHelper helper, string imageRelativeUrl, string altText)

{

StringBuilder htmlBuilder = new StringBuilder();

HtmlTextWriter writer = new HtmlTextWriter(new StringWriter(htmlBuilder));

writer.AddAttribute(HtmlTextWriterAttribute.Src, GetImageUrl(imageRelativeUrl));

writer.AddAttribute(HtmlTextWriterAttribute.Alt, altText);

writer.RenderBeginTag(HtmlTextWriterTag.Img);

writer.RenderEndTag();

writer.Flush();

return htmlBuilder.ToString();

}

Unlike the framework writer, you’re not constrained to specify attributes in any particular order, and tags which aren’t nested can be written with a single WriteTag(), rather than BeginTag() and EndTag() calls. The writer copes with multi-level tag hierarchies – this sample builds a Superfish CSS menu:

FluentHtmlTextWriter writer = FluentHtmlTextWriter.Begin();

writer.BeginTag(HtmlTextWriterTag.Ul)

.WithAttribute(HtmlTextWriterAttribute.Id, “menu.Name”)

.WithAttribute(HtmlTextWriterAttribute.Class, “sf-menu sf-vertical”);

.BeginTag(HtmlTextWriterTag.Li)

.BeginTag(HtmlTextWriterTag.A)

.WithAttribute(HtmlTextWriterAttribute.Class, “sf-with-ul”)

.WithAttribute(HtmlTextWriterAttribute.Href, “#”)

.WithValue(“Link 1”)

.WriteTag(HtmlTextWriterTag.Span)

.WithAttribute(HtmlTextWriterAttribute.Class, “sf-sub-indicator”)

.WithValue(“»”)

.EndTag()

.EndTag()

.EndTag();

string html = writer.End();

Assert.AreEqual(“<ul id=\”menu.Name\” class=\”sf-menu sf-vertical\”>\r\n\t<li><a class=\”sf-with-ul\” href=\”#\”>Link 1<span class=\”sf-sub-indicator\”>»</span></a></li>\r\n</ul>”,

html);

The HtmlTextWriter equivalent is unthinkable.

Patrik H%u00e4gne has an alternative fluent HtmlTextWriter implementation, which is nicely put together, but I wanted slightly different functionality. Firstly I wanted to get the HTML string from the writer directly, without needing to instantiate a StringBuilder and StringWriter. Secondly I wanted minimal new code – Patrik uses a separate class to manage writing attributes, and has specific functions for known tag types. Thirdly, I didn’t really like Patrik’s syntax, with the need to specify the tag type when you write an end tag – and when tags aren’t nested, I wanted to write them in a single unit:

string html = FluentHtmlTextWriter.Begin()

.WriteTag(HtmlTextWriterTag.Span)

.WithAttribute(HtmlTextWriterAttribute.Id, “id_span”)

.WithValue(“contents_span”)

.End();

Assert.AreEqual(“<span id=\”id_span\”>contents_span</span>”, html);

My version is on MSDN Code Gallery here: FluentHtmlTextWriter. It works by building up a list of actions when you start writing a tag, and flushing them in the correct order to an internal HtmlTextWriter when you start writing the next tag. When you call End() it flushes the internal writer and outputs its contents. An alternative constructor lets you write directly to an output stream, in which case you can Flush() the writer and don’t need to call End().

The current implementation only deals with basic tag, attribute and style functionality, and doesn’t include optional HTML encoding overloads. It’s only 75 lines of code, and extending it should be trivial.

There is a negligible performance hit in using FluentHtmlTextWriter – running the image tag generation code above 20,000 times on my dev machine, the fluent version takes between 0.01and 0.02 seconds longer than the framework version (on average 0.07 seconds compared to 0.05).

TechEd 2009 – Exam Cram Night – 70-630 MCTS- Microsoft Office SharePoint Server 2007

Last night we had an exam cram, where keen and interested delegates bunkered down
and got their neurons firing.

I went through this exam with them giving them tips and sharing my general SharePoint
knowledge around this.

Today – the good news was that I passed three delegates whom took the exam *today*
and all passed!!! Well done guys!

Here’s the ppt deck that I used – enjoy and well done all!

PPTs

TechEd 2009 – SOA314 – BizTalk Goes Mobile

We’re in the thick of TechEd 2009 here in Australia on the Gold Coast (tough place
to have a conference 😉 Sun, sand and a beach that stretches for miles 1 block away)

Big thanks to those of you that attended my session – great turn out and all my demos
worked like a charmthat doesn’t happen every day 🙂

Here’s the powerpoints and demo files:

PowerPoints  –

MicksDemoFiles.zip

>

MicksDemoFiles.zip

>

A possible HL7 pipeline wives’ tale

I just got the HL7 DASM pipeline working with two custom Decode pipeline components (String Replace and Archive).

I was receiving batched messages, and if there was an error in any of the trigger messages, the entire batch was being rejected with no discernable error message other than the context property: ParseError=True (wow, I can really troubleshoot with that indicator)

So I was given hotfix KB 973910 and started testing it. I did not seem to fix the problem.

I changed and used the out of the box HL7 DASM, and it started working (debatching the file and suspending only the trigger message that was actually in error). I decided to rebuild the custom pipeline, I removed the HL7 DASM pipeline component from the .btp file, removed the HL7 DASM from the tool box, and the re-added the pipeline to the tool box and then added it to the .btp file. I then deployed it and ran a file through successfully.

Here is the wives’ tale: If you have a custom HL7 pipeline component, you need to remove the HL7 DASM completely from Visual Studio and then re-add it so that BizTalk will see the new behavior.

Please let me know if this is a fallacy, and what the minimum amount of work that I have to do to have BizTalk see a newly hotfixed pipeline component.

ANTS Profiler 5.1 and Windows Process Activation Services (WAS)

I have been using ANTS Profiler to conduct some profiling against some WCF services hosted on Windows 2008 that I have been working on. This was working pretty well with services hosted in IIS, but I was experiencing some difficulties when attempting to hook it all up with WCF services hosted in WAS using the net.tcp binding. I still don’t have a definitive answer as to why I have been experiencing issues, but I have a workaround procedure in order to get it working.


Firstly, you need to create a profile and choose the Windows service application type to profile, selected WAS from the, as shown in the following screen capture.



Once you click the Start Profiling button the WAS service should be stopped and started. It is at this point where I experience my first problem, as it seems to hang at the starting state. Note the status bar in the following screen capture.



Now it appears that the service never starts and this state is also shown when you browse the Windows Process Activation Service service in the Services snap-in. After a bit of playing around I managed to get past this issue, by following these simple steps:


1.       Execute iisreset from a command prompt window


2.       Once iisreset has restarted, browse to an HTTP WCF endpoint on the server


3.       The profiler should now be started


Now, at this point I also experienced an issue when attempting to take a memory snapshot, receiving the following error message where <some folder> is the location where it is trying to save the data.


Could not start profiling as the processing being profiled was unable to create the file ‘<some folder>’.You can set the RGTEMP or the RGIISTEMP environment variables in the System control panel to override the location used for profiler results files.


In order to get around this I simply gave everyone permissions to the folder it was trying to save to. I am sure there was a more focused way that this could be achieved, but as this was a development machine I was quite happy with this.

Fluent DAL Mapping

If you spend some time using Fluent NHibernate, you’ll want to use its neat style of mapping for all data access, even when you’re working against traditional DALs. I’ve put a sample up on MSDN Code Gallery for this scenario, using a fluent style of mapping between domain objects and data readers populated by stored procedure calls.
The interface is very similar to FNH, with a mapping class used for each domain entity – this is a simple mapping class:
public class PostCodeMap : DataReaderMap<PostCode>
{
public PostCodeMap()
{
Map(x => x.InwardCode, “PS_IN”);
Map(x => x.OutwardCode, “PS_OUT”);
}
}
The string constants define the column names expected in the data reader, and the base class takes care of running the map. For more complex entities, DataReaderMap also includes mapping via a conversion function:
Map<string, bool>(x => x.Activated, “AccountActivated”, Legacy.FromBoolean);
– where the mapping specifies to and from types, and a delegate to invoke for the conversion (in this case, a method which converts a legacy string representation of a boolean – Y/N – to a bool).
For composite objects, the base map includes referencing, for cases where the child entity is loaded from the same data reader as the parent entity:
References(x => x.Address, new AddressMap());
Where the child entity is read from a separate data reader, then the composition needs to be done outside of the map in a repository or an assembler component. The Load class isolates calling the stored procedure, so you get a fluent interface for populating domain objects, and collections of objects:
public User GetUser(Guid userId)
{
//populate basic details:
User user = Fluently.Load<User>().With<UserMap>()
.From<GetUser>(i => i.UserId = userId,
x => x.Execute());
//add accounts:
user.Accounts = Fluently.Load<List<Account>>().With<AccountMap>()
.From<GetUserAccounts>(i => i.UserId = userId,
x => x.Execute());
return user;
}
The From() call specifies the type of stored procedure, an action to populate the object, in this case setting up the UserId parameter, and a function to call which returns a data reader, in this case Execute().
The full sample is on the gallery here: Fluent DAL Mapping . It’s a simple task to extend the sample to load datasets, or to populate update procedure calls from entities. If your database is sufficiently conventional this could be extended to provide FNH-style auto-mapping, reflecting over entities and using conventions to map properties to column names.

Notification when Receive Locations/Send Ports change

Instead of scanning the Event Log and capturing when the Receive Locations or Send Ports go down, you can use the following triggers to send out an email when they change status:

Receive Location:

CREATE TRIGGER [dbo].[ReceiveLocationChangeNotification] 
   ON [dbo].[adm_ReceiveLocation]
   AFTER UPDATE
AS 
BEGIN
  -- SET NOCOUNT ON added to prevent extra result sets from
  -- interfering with SELECT statements.
  SET NOCOUNT ON;

    DECLARE @oldstatus int
  DECLARE @newstatus int
  DECLARE @ReceiveLocationName nvarchar(256)
  DECLARE @status nvarchar(10)
  DECLARE @message nvarchar(300)
  --Was the status not changed
  IF NOT UPDATE([Disabled])
  BEGIN
  RETURN
  END
  --Otherwise send out email
  select @oldstatus=(select [Disabled] from Deleted)
  select @newstatus=(select [Disabled] from Inserted)
  select @ReceiveLocationName=(select [Name] from Inserted)
  SET @message=@ReceiveLocationName+' recieve location changed from '+ case
                     when @oldstatus=-1 then 'Disabled'
                    when @oldstatus=0 then 'Enabled'
                    END + ' to ' +
                    case
                    when @newstatus=-1 then 'Disabled'
                    when @newstatus=0 then 'Enabled'
                    END 
                EXEC msdb.dbo.sp_send_dbmail @recipients='[email protected]',
                @subject = @message,
                @body = @message,
                @body_format = 'HTML' ;

--  print @message

END
GO

Send Port:

CREATE TRIGGER dbo.SendPortChangeNotification 
   ON dbo.bts_sendport
   AFTER UPDATE
AS 
BEGIN
  -- SET NOCOUNT ON added to prevent extra result sets from
  -- interfering with SELECT statements.
  SET NOCOUNT ON;

    DECLARE @oldstatus int
  DECLARE @newstatus int
  DECLARE @PortName nvarchar(256)
  DECLARE @status nvarchar(10)
  DECLARE @message nvarchar(300)
  --Was the status not changed
  IF NOT UPDATE(nPortStatus)
  BEGIN
  RETURN
  END
  --Otherwise send out email
  select @oldstatus=(select nPortStatus from Deleted)
  select @newstatus=(select nPortStatus from Inserted)
  select @PortName=(select nvcName from Inserted)
  SET @message=@PortName+' changed from '+ case
                     when @oldstatus=1 then 'Unenlisted'
                    when @oldstatus=2 then 'Stopped'
                    when @oldstatus=3 then 'Started'
                    END + ' to ' +
                    case
                    when @newstatus=1 then 'Unenlisted'
                    when @newstatus=2 then 'Stopped'
                    when @newstatus=3 then 'Started'
                    END 
                EXEC msdb.dbo.sp_send_dbmail @recipients='[email protected]',
                @subject = @message,
                @body = @message,
                @body_format = 'HTML' ;
  
    --print @message

END
GO

(Did I mention the disclaimer noted on the right side of this blog?)