Resolving Special Folders in WiX 3.0

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

One of the frustrations of working with WiX is that when you want to do something out of the ordinary, chances are it’s provided somewhere in a WiX extension, but unless you trawl through the XSDs you’re not likely to find it. I had this issue when I wanted to resolve the special folder My Music through WiX, so I could put the full path into a config file.

Various special folders are already available as properties to the installer, including My Documents and My Pictures, but not My Music. Adding an extension to expose Environment.GetSpecialFolder() to WiX is a trivial implementation in a couple of classes (comments omitted for brevity):

public class EnvironmentExtension : WiXExtension

{

private EnvironmentPreprocessorExtension preprocessorExtension;

public override PreprocessorExtension PreprocessorExtension

{

get

{

if (this.preprocessorExtension == null)

{

this.preprocessorExtension = new EnvironmentPreprocessorExtension();

}

return this.preprocessorExtension;

}

}

}

public class EnvironmentPreprocessorExtension : PreprocessorExtension

{

private const string SPECIALFOLDER = “specialFolder”;

public override string[] Prefixes { get { return new string[] { SPECIALFOLDER }; } }

private List<string> _specialFolders;

private List<string> SpecialFolders

{

get

{

if (_specialFolders == null)

{

_specialFolders = new List<string>(Enum.GetNames(typeof(Environment.SpecialFolder)));

}

return _specialFolders;

}

}

public override string GetVariableValue(string prefix, string name)

{

string result = null;

if (prefix == SPECIALFOLDER && SpecialFolders.Contains(name))

{

Environment.SpecialFolder specialFolder = (Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), name, true);

result = Environment.GetFolderPath(specialFolder);

}

return result;

}

}

Reference the folder you want from the Environment.SpecialFolders enum as a property in your WiX script:

<Property Id=MUSICPATH Value=$(specialFolder.MyMusic)/>

– and add the extension assembly to your light and candle calls, making sure the DLL is available at runtime :

candle -out x.y.z.WiXobj x.y.z.wxs -ext EnvironmentExtension

light -out x.y.z.msi x.y.z.WiXobj -ext EnvironmentExtension -cultures:en-us

But I suspect it’s already available somewhere in WiX.

Serialising Microsoft StreamInsight QueryTemplates

At first sight, StreamInsight doesn’t appear to offer any support for dynamic queries. Once you have got over the initial ’wow’ factor of creating continuous queries over streams using LINQ, rather than some SQL dialect or specialised DSL, the reality hits you that your query is just code. You wrote the LINQ using C# or VB.NET, and you ended up compiling it into some assembly.

That’s all very well, but it’s not very flexible. How are you going to store and manage your queries in a repository so that you can review, change and version them? Does Microsoft really expect you to recompile and re-deploy assemblies every time you want to create or change a query in StreamInsight? Surely you should be able to dynamically deploy queries straight from a repository.

Have no fear. All is well. The QueryTemplate is serialisable. It isn’t serialisable in the .NET sense (i.e., it isn’t marked up as serilaisable, and it doesn’t implement ISerializable). Rather, it implements the QueryTemplate.Definition property which returns an XML document containing a complete rendering of your template, complete with a full dataflow and all the operators. To deserialise the XML, you use Application.CreateQueryTemplate. You have to pass in an XmlReader that you have created over the XML. You get back a clone of the original QueryTemplate which you can now bind to input and output adapters and emit to the engine as a Query. Nothing could be simpler.

There are a couple of gotchas. First, don’t do what I did while experimenting. I created a QueryTemplate and serialised it to XML. I then tried to deserialise it as a second, identical, QueryTemplate in the same Server instance. I got back an InvalidDefinition error. It seems you can’t have identical QueryTemplates in a single StreamInsight Server instance.

The second thing to note is that the serialised QueryTemplate does not contain fully qualified references to your event types. You still have to define the event types in your application by calling the CreateEventType method. If you plan to store QueryTemplate XML in some custom repository, you will also need to store the fully qualified names of the .NET types your have defined for your events. Of course, you will also need to ensure that these types are available at runtime.

Much the same argument applies to adapters. The QueryTemplate XML does not contain any information on which input and output adapters you want to bind to your query. However, once you realise that your QueryTemplates are serialisable, it is simple to work out how you might store and manage the template in some repository together with event type and adapter information. All this information, taken together, defines the StreamInsight concept of a query. You can write code to extract it from the repository at run-time and run the query.

The current CTP is just a glorified SDK. Will Microsoft provide a repository and tooling in the release version? I have no idea. Given the freedom StreamInsight offers in terms of event definition, and given the fact that the engine can be hosted in custom applications, it is difficult to see how Microsoft could provide a totally generic end-to-end solution that would support externalisation of queries in any and all circumstances. They could provide a repository and API, and leave it to developers to write the code to exploit the repository. However, you would still need to write the LINQ together with code to create QueryTemplates and extract and upload XML to the repository.

What does OCS setup look like to Asterisk 1.6?

Well folks after my last tutorial, Finally
Connected OCS to Trixbox I’m getting more and more questions about the OCS side
of thingsso I thought I’d expand on our OCS 2007 R2 side of the setup.

So the internal setup looks a little like this:

So here our IP:Z = 10.1.1.30 which makes sense when looking at the OCS machines from
Trixbox as follows:

Note the 10.1.1.30 or IP:Z in the hosts list here from Trixbox. In
short – as far as OCS is concerned when Chatterphone gets a request
(from either internal or external) it *has* to have all the knowledge to work out
where to route the call.

So don’t forget that OCS embeds a VOIP phone details into User Accounts within AD
– viewing the user class object will give you the right details. I wrote a webservice
that will display the user’s phone numbers etc.

I also wrote a quick WebService to pull out phone and sip address
details from AD from a search string. So if you supply part of a phone number, it
gives you the users, and if you have a sip address, it give you the phone number.
(I was going to use it for a lookup from Trixbox cause from OCS Communicator, I couldn’t
get the invite another person to the conf call via phone working – it was sending
an invalid CallerID out to our PSTN provider)

Download File – OcsHelperService

(source code included – as is, for a guide 🙂

Example calls:
I’ve installed it onto a site called ’ocsservices.office.breeze.net’ and
you can run it as follows:

  1. Lookup a Phone Number from SIP Address
    1. http://<webServer>/OcsHelperService/Lookup.svc/Process?action=getphone&caller=<sip address
      – minus ’ sip:’> e.g. mickb@acme.com
  2. Lookup a SIP Address from a Phone Number
    1. http://<webServer>OcsHelperService/Lookup.svc/Process?action=getaddr&caller=<start of
      a user’s voip number>
  3. >

    Let’s start

    Learning – What in the World is OCS doing?

    Setup meaningful logging to try and work out what Trixbox<->OCS is doing = MediationServer

    1. From the OCS Management Tool – setup a New Debug Session
    2. From the OCS 2007 R2 Logging Tool – log S4 and the Mediation Server settings.
    3. Then click Start Logging and you should be on your way to recording
      what OCS is doing in response to Trixbox. This helps you find out *exactly* what OCS
      is responding with. Calls, “No Service” etc.
    4. Go through and run through a test session of what you’re wanting to try out. e.g.
      incoming call or outgoing call.
    5. Click Stop Logging and click Analyze Log Files
    6. The OCS 2007 R2 SDK tool – snooper should come to the rescue here
      and display a detailed log of what happened. Colour coded and see what what going
      on.
    7. Here’s a sample for an outgoing call:
    8. What’s more interesting is an incoming call:
    9. In this particular call – I rang my OCS number and hung up after 2 rings. The conversation
      is pretty detailed in terms of what you see with SIP. i.e. Seeing this is the MediationServer there
      should be something like SIP INVITE->Trixbox->SIP INVITE->OCS Mediation
      (Chatterphone)->OCS Server
      .
      You’ll notice these packets are like IP4 routing packets, with headers possibly changing,
      but you should be able to make out your dialled number in there.

      >

      This is your handy weapon for OCS land – if communication isn’t getting through, then
      check all the IP details.

      Incoming calls to OCS

      1. Users are generally identified as +<country code><area code><number>
      2. If when making an External Call in, make sure in the above logs the number
        coming in is in the right format. i.e. +612.@acme.com
      3. What does a User Look Like
        1. Firstly they belong to a Location (the Location Name also has implications within
          ExchangeUM if you use it for Voice Mail), looking at the location code I just have
          it stock standard as follows:
        2. Finally let’s look at what a user like myself looks like from the OCS Admin Tool.
          (In my case Enterprise Pools->BreezePool1->Users)

        >

        Hopefully this has helped a little more in working out what is going on in your OCS
        world(s).

        Between the logging here and the ’Asterisk -r’ option in a console app on Trixbox,
        you should be getting a better picture. Because many setups can be very different,
        looking down here at the ’packet’ level is really the only way to go in resolving
        these.

        (Another handy option is to turn on Event Logging in OCS Communicator, which gives
        some great info from a client perspective as well 🙂

        Good luck. 🙂

        Mick.

Update on SOA Conference and Upcoming Events

Over the past few months we have talked to a number of customers and partners about our plans for upcoming Service Oriented Architecture (SOA) events.  We have heard loud and clear that travel budgets are limited, and have evaluated the various ways we can share Real World SOA best practices and training to our customers and partners.  As a result of these discussions we have decided not to host the Microsoft SOA conference this year; instead, we will deliver SOA related sessions (including sessions on BizTalk Server, .NET, Visual Studio and SharePoint Server content) at the Microsoft Professional Developers Conference in Los Angeles (November 17 – 19) and at TechEd EMEA in Berlin, Germany (November 9-13).

Today we are also announcing that we will be bringing a “Business Integration” road show to visit many major cities around the world, which will help us dialog with customers and partners who are not able to travel in this economic climate. 

For more details or to register to one of the road show events please see our Business Integration Road Show site.

Technorati Tags: SOA,BizTalk,Conference,Road Show,PDC,TechEd

XPATH 1.0 XSLT 1.0 Return elements or attributes based upon a max date

While working for a client we had to use some custom XSLT within BizTalk to complete some requirements that was outside the bounds of the BizTalk Mapper and orchestrations. Along with what we were already doing the client came to us and wanted a value assigned to an attribute based up on the most recent input file that had been dropped so essentially based upon the a max date from an array of dates. Come to find out that XPATH 1.0 and XSLT 1.0 can’t select records based upon a max date. Here is how I solved this problem.

I made some generic samples to help explain. Here is a sample input document.



<?xml version="1.0" encoding="utf-8"?>
<BatchedFile>
  <Record>
    <InformationElement Date="12/09/2008" ID="TryAgain" />
  </Record>
  <Record>
    <InformationElement Date="11/11/2008" ID="TryAgaine" />
  </Record>
  <Record>
    <InformationElement Date="01/08/2008" ID="TryAgain" />
  </Record>
  <Record>
    <InformationElement Date="03/09/2008" ID="TryAgain" />
  </Record>
  <!-- I Want to pick the following record ID because it is the most recent date- -->

  <Record>
    <InformationElement Date="01/09/2009" ID="YouPickedTheRightOne" />
  </Record>
  <Record>
    <InformationElement Date="07/09/2008" ID="TryAgain" />
  </Record>
  <Record>
    <InformationElement Date="12/09/2008" ID="TryAgain" />
  </Record>  
</BatchedFile>

The trick is to try and compare the dates. XSLT can’t make an array exactly but you can use variables in a similar way and use the node-set() function to select the values within the variable.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl userCSharp" xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp" >
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="BatchedFile">
      <!-- First Create a variable that stores the Date Attribute along with its corresponding absolute value-->
      <xsl:variable name="MaxDateRecord">
        <xsl:for-each select ="./Record/InformationElement/@Date">
          <TotalDays>
            <xsl:attribute name ="RecordDate">
              <xsl:value-of select ="self::node()"/>
            </xsl:attribute>
            <!--Please see below for explanation of totalDays function-->
            <xsl:value-of select ="userCSharp:totalDays(self::node())"/>            
          </TotalDays>          
        </xsl:for-each>       
      </xsl:variable>
      <!--I decided to create a variable that stored the most recent date, its easier to debug-->
      <xsl:variable name ="MostRecentDate">
        <!--The predicate after TotalDays is what picks the highest number value, which then corresponds to a date-->
        <xsl:value-of select ="msxsl:node-set($MaxDateRecord)/TotalDays[not(. &lt; preceding-sibling::TotalDays or . &lt; following-sibling::TotalDays)]/@RecordDate"/>
      </xsl:variable>
      <!-- Here is where the output is generated, -->
      <MaxDate>
        <xsl:attribute name="DidIPickTheRightOne">
          <xsl:value-of select ="//InformationElement[@Date=$MostRecentDate]/@ID"/>
        </xsl:attribute>
      </MaxDate>
    </xsl:template>
  <msxsl:script language="C#" implements-prefix="userCSharp">
    <!-- This function takes a date like 09/01/2008 
    and returns the number days that exist between 01/01/1990 
    and the current date selected. Any date would work as a reference
    date.-->
    <![CDATA[
 public static string totalDays(string date)
        {
            DateTime d1 = new DateTime();
            DateTime d2 = new DateTime(1990, 01, 01);
            TimeSpan span = new TimeSpan();
            DateTime.TryParse(date,out d1);            
            span = d1 - d2;
            return span.TotalDays.ToString();
            
        }       
]]>
  </msxsl:script>
</xsl:stylesheet>

Okay here is an explanation of what is going on.

1. I first create a variable (MaxDateRecord) that stores the date value of each record as well as the number of days between that date and Jan 1, 1990. This gives me a numeric value that XSLT can compare.

a. Here is what MaxDateRecord would look like essentially after it had ran through all the iterations of the Record element.

<MaxDateRecord>
<TotalDays RecordDate="12/09/2008">6917</TotalDays>
<TotalDays RecordDate="11/11/2008">6889</TotalDays>
<TotalDays RecordDate="01/08/2008">6581</TotalDays>
<TotalDays RecordDate="03/09/2008">6642</TotalDays>
<TotalDays RecordDate="01/09/2009">6948</TotalDays>
<TotalDays RecordDate="07/09/2008">6764</TotalDays>
<TotalDays RecordDate="12/09/2008">6917</TotalDays>
</MaxDateRecord>

2. I then compare all of the TotalDays and find the largest one and select out the RecordDate that matches.

a. The MostRecentDate variable outputs “01/09/2009” in Visual Studio.

3. After that its an easy process of selecting the Record element with the corresponding MostRecentDate or in this case the ID of that element.

<?xml version="1.0" encoding="utf-8"?>
<!-- This is what my output should be -->
<MaxDate DidIPickTheRightOne="YouPickedTheRightOne" />

I hope I have saved some of you some time. Since BizTalk 2009 still uses the 1.0 specification of XSLT and XPath, I was somewhat disappointed to find out there was no direct way to get this done. I know there are better ways to handle the logic I wrote in XSLT so if you have suggestions or criticisms, post them.

I have to give some thanks to Jirka Kosek for the article “Understanding the node-set() Function” http://www.xml.com/pub/a/2003/07/16/nodeset.html

as well as lhaeger for the article “Again! The power of XPATH or the missing max() function” http://www.novell.com/communities/node/6431/again-power-xpath-or-missing-max-function

Debugging an external assembly that’s called from within a BizTalk process

Debugging an external assembly that’s called from within a BizTalk process

External assemblies are being called from within BizTalk orchestrations in almost every BizTalk application. Knowing how to debug them is important. This guideline will show you how you can debug those external assemblies on your workstation or a remote box using a very simple sample application. Debugging external assemblies on a local box with one […]

Announcing the WebsiteSpark Program

I’m excited to announce a new program – WebsiteSpark – that Microsoft is launching today.

WebsiteSpark is designed for independent web developers and web development companies that build web applications and web sites on behalf of others.  It enables you to get software, support and business resources from Microsoft at no cost for three years, and enables you to expand your business and build great web solutions using ASP.NET, Silverlight, SharePoint and PHP, and the open source applications built on top of them.

What does the program provide?

WebSiteSpark provides software licenses that you can use for three years at no cost.  Once enrolled, you can download and immediately use the following software from Microsoft:

  • 3 licenses of Visual Studio 2008 Professional Edition
  • 1 license of Expression Studio 3 (which includes Expression Blend, Sketchflow, and Web)
  • 2 licenses of Expression Web 3
  • 4 processor licenses of Windows Web Server 2008 R2
  • 4 processor licenses of SQL Server 2008 Web Edition
  • DotNetPanel control panel (enabling easy remote/hosted management of your servers)

The Windows Server and SQL Server licenses can be used for both development and production deployment.  You can either self-host the servers on your own, or use the licenses with a hoster.  WebsiteSpark makes it easy to find hosters who are also enrolled in the program, and who can use your licenses to provide you with either dedicated or virtual dedicated servers to host your sites on.

In addition to software, WebsiteSpark provides partner opportunities to grow and build your business (including customer referrals through our partner programs).  It also includes product support (including 2 professional support incidents) and free online training for the products.

Who can join the program?

WebSiteSpark is available to independent web developers and small web development companies.  The only two requirements to join the program are:

  1. Your company builds web sites and web application on behalf of others.
  2. Your company currently has less than 10 employees.

If you meet these requirements you can visit the WebsiteSpark website and sign-up today. 

As part of the enrollment process you can pick either a network referral partner (for example: a hoster or an existing Microsoft partner), or enter a referral code that you have received at an event or from a Microsoft employee.  If you send mail to webspark@microsoft.com you can get a referral code quickly.  You can then use that code to enroll in the program on the WebsiteSpark website.  Once enrolled you can immediately download and use the software, as well as begin to participate in the network/partner opportunities.

If you have any problems enrolling, you can also send me mail (scottgu@microsoft.com) and I can connect you with someone who can help. 

What happens after the 3 years?

WebsiteSpark is a 3 year program.  There is no obligation to continue to use any of the software after the three years is over, and there are no costs for the three years other than a $100 program fee at the end of the three years.

At the end of the three years, WebsiteSpark participants can optionally choose to purchase all of the software in the WebsiteSpark program via a $999/year package.  This includes 3 copies of VS Professional, 1 copy of Expression Studio (including Blend and Sketchflow), 2 copies of Expression Web, and 4 processor licenses of Windows Web Server 2008 and 4 processor licenses of SQL Server Web edition that can be used for production deployment.

Alternatively, if you want to purchase only the production server licenses, you can take advantage of a $199/year offering that includes both 1 Windows Web Server processor license and 1 SQL Server Web edition processor license.  You can buy the quantity you need of this package at $199/year each. 

Summary

The WebsiteSpark program joins the other two successful “Spark” programs we’ve previously launched – BizSpark for startups, and DreamSpark for students.

Coming at a time when the current economic climate is still tough, WebsiteSpark will help support developers and companies by providing the business resources, training, and software necessary for companies to get started and grow successful businesses on the Microsoft Web Platform.

Visit www.microsoft.com/web to learn more about the Microsoft Web Platform, as well as download and install the new Microsoft Web Platform Installer V2 we released today – which makes it really easy to quickly provision web servers and web development machines.  You can then browse and download and use open source web applications from the Windows Web Application Gallery.

Hope this helps,

Scott

P.S. In addition to blogging, I have been using Twitter more recently to-do quick posts and share links.  You can follow me on Twitter at: http://www.twitter.com/scottgu (@scottgu is my twitter name)

Lazy-Loading with Object Extensions

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

If you make heavy use of lazy-loaded properties, the repetitive if-backing-field-null-then-instantiate code can be centralized in an extension method on the object class:

/// <summary>

/// Extension methods for <see cref=”Object”/>

/// </summary>

public static class ObjectExtensions

{

/// <summary>

/// Lazy-loads a property

/// </summary>

/// <typeparam name=”T”>Type of property</typeparam>

/// <param name=”obj”>Extended object</param>

/// <param name=”field”>Property backing field</param>

/// <param name=”load”>Property loading function</param>

/// <returns>Lazy-loaded property</returns>

public static T LazyLoad<T>(this object obj, ref T field, Func<T> load)

{

if (field == null || field.Equals(default(T)))

{

field = load();

}

return field;

}

}

Classes then define lazy-loaded properties using the extension method, specifying the backing field and the method used to populate it:

protected List<MediaItem> AllItems

{

get

{

return this.LazyLoad<List<MediaItem>>(ref this._allItems,

() => new List<MediaItem>());

}

}

– rather than:

protected List<MediaItem> AllItems

{

get

{

if (this._allItems == null)

{

this._allItems = new List<MediaItem>();

}

return this._allItems;

}

}

Only a tiny enhancement, but it isolates some general code and reduces the chances of causing an infinite loop by typing the property name rather than the field name.