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. [email protected]
  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. [email protected]
      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 [email protected] 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 ([email protected]) 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.

A proposed introduction…

What a pity. I’ve spent some time recently evaluating SQL Server 2008 Reporting Services with respect to its proposed use on a UK public sector project that will implement a part of the ‘national infrastructure’. In every respect but one, Reporting Services provides an excellent fit for the stated requirements. There is already a commitment to using SQL Server, and SharePoint, within the project, so Reporting Services appears the way to go.

What is the exception? Well, Reporting Services provides a nice little tool called ‘Report Builder’ for creation, amongst other things, of ad hoc reports. This is a user-friendly little gizmo that can be downloaded directly from the portal via Microsoft’s excellent ClickOnce technology. ClickOnce ensures that the application is installed in a sandboxed fashion under the current user’s profile, and does not interfere with other installations for other users.

All good stuff, except that the proposed system needs to provide ad hoc reporting facilities to a number of different agencies across the UK. Oh, and it must be formally accredited by the security people before it can go live. It turns out that there is no prospect that they will agree to installation of any software on client desktops at those agencies. Not even using ClickOnce. It’s out of the question.

SAP offers a similar toolset to Reporting Services, but they have a tool for designing ad hoc reports that is entirely browser-based and has zero footprint on the client.

Mmmm. Time for the Microsoft SQL Server product team to meet Ajax, methinks.