BizTalk: Naming convention for the BizTalk solutions

Version 2.0, 2009-07-30
1 How to use this document
To accommodate this document for the specific solution:
%u00b7 Create the real names in Appendix or create a separate Dictionary document. See Instructions in Appendix.
%u00b7 Review the text, marked with [TBD] flag, and change it for your case.
The “Naming guidelines for the .NET Framework types” [ http://msdn.microsoft.com/en-us/library/xzf533w0(VS.71).aspx ] are used as a basis of this document. Also see the “Naming Convention” in Wikipedia [ http://en.wikipedia.org/wiki/Identifier_naming_convention ]
Names should be short, sortable, readable, discoverable, and self-described.
The main test for constructing name rule should be in questions:
%u00b7 In what kind of places can I see this name?
%u00b7 How easily can I work with the names in these places?
Work” means to read, to find, and to understand sense without errors. Usually we work with names in lists. Think about these places like about namespaces in programming languages.
Short names:
  • Create as short as possible name.
  • Use abbreviations only in restricted cases. See article the “Abbreviationshttp://msdn.microsoft.com/en-us/library/141e06ef(VS.71).aspx
  • Use prefixes and suffixes only to differentiate names.
  • If you see one word in several places of the full name, consider this as a bad signal. Try to redesign the terms used in the names.
Sortable:
  • Create “sortable” name. That means using more generic/important part of the name in the leftmost position. For example, prefer the name Folder_20090515 than the name Folder_05_15_2009.
Readable:
  • Use the name case compatible with the well-known practices in programming languages/protocols with respect to upper and lower cases. For instance, the target namespaces (URL) should be in lower case format, but the other names should be in the Pascal format. See the “Capitalization Styles” article [http://msdn.microsoft.com/en-us/library/x2dbyw72(VS.71).aspx ]
    If the word with specific case is widely used in company, don’t force to change it to the Pascal format.
  • Decorate infixes, prefixes or suffixes with lower case and with undrscore. For example: TicketBatch_type, Source1 _and_Source2_to_Target, msg_MyRequest.
Discoverable:
  • The name should be discoverable. That means we easily should understand by the name of the artifact where we can find the artifacts or additional information about it. Names should link artifacts. Say, the schemas with target namespace the http://domain.company.com/solution/project/2009-05-14 definitely should be in the project the Company.Domain.Solution.Project and in assembly the Company.Domain.Solution.Project.dll.
Self-described (Semantics):
  • Create name form the “business point of view” not form the “developer point of view”, especially the name exposed outside solution.
  • Don’t use generic terms in the names. Examples: Send, Receive, Service, Message, Transformation, Schema, Map, Orchestration, BizTalk.
  • Place a frequently used term into the shared dictionary with comment about where do use it and do not use.
  • Several artifacts have the full names (composited names) and short names. Usually we can easily understand what name we use in the specific context.
%u00b7 If we need to add one or more logical grouping into the name, use the composited names created with words separated with dot. In specific contexts the separation symbol can be different, like underscore, dash or backslash. Each <ShortName> can be a composite name. Composite names can be used for each part of the full names, as Company, Domain, Solution, and Project. For example, you can use name the Schemas.Niem for the project short name.
3 General names
3.1 Syntax
<Company>
<Domain>
<Solution> =:
<Company>.<Domain>.<SolutionShortName>
<Project> =:
<Solution>.<ProjectShortName>
3.2 Examples
%u00b7 Solution name: short name –MySolution, full name – MyCompany.MyDomain.MySolution
%u00b7 Project name: short composite name – Schemas.Niem; full name – MyCompany.MyDomain.MySolution.Schemas.Niem
4 Names inside BizTalk Solutions
We use term the solution in the Visual Studio meaning, it is a name of the solution we see in the Solution Explorer window in the Visual Studio. Sometimes we mix solution and project terms but not in this document.
BizTalk application is named as solution.
<Solution> =:
<Company>.<Domain>.<SolutionShortName>
<ApplicationName> =: <Solution>
For example, for the MySolution solution use the MyCompany.MyDomain.MySolution full name.
4.2 Projects, Assemblies, .NET namespaces
We use term the project in the Visual Studio meaning, it is a name of the project we see in the Solution Explorer window in the Visual Studio.
<Project> =:
<Solution>.<ProjectShortName>
<AssemblyName> =: <Project>
<Namespace>=: <Project>
For example, for the MyProject project use the MyCompany.MyDomain.MySolution.MyProject project full name, the MyCompany.MyDomain.MySolution.MyProject assemblyname, and the MyCompany.MyDomain.MySolution.MyProject namespace.
We should separate the .NET namespaces and the target namespaces. They are different things and used in different places. For brevity we use term the namespace exactly for the .NET namespace!
Note: After creating a new project, copy the project name property to the project properties the “Assembly Name” and the “Default Namespace”.
Use the predefined folder structure on all development machines and, if it is possible, on the Test and Product servers. This eliminates the errors and deployment effort because several BizTalk artifacts use the absolute file paths in configuration.
<SolutionsRootFolder> =: c:\Solutions
<SolutionFolder> =:
<SolutionsRootFolder>\<Solution>
<ProjectFolder> =:
<SolutionFolder>\<ProjectShortName>
For example, the MyCompany.MyDomain.MySolution.MyProject project is placed in the c:\Solutions\MyCompany.MyDomain.MySolution\MyProject folder.
Use very strict rules for the target namespaces, because the XML schemas expose the data interfaces to the outer world. The target namespaces should follow the industry standards and the corporate standards. Because the exposed interfaces are immutable, we should use versioning for target namespaces.
We must use the URL and URN formats to target namespaces. Feel free to use one of these standards. See the “Namespaces in XML 1.0 (Second Edition)http://www.w3.org/TR/xml-names/ for more information.
[TBD: Here I use the URL reverse order for the target namespaces. Not for the full name but for the “before-solution” part of the name, for the first part of the name before first backslash. If you don’t want to use target namespaces that works as the web addresses, consider to use the target namespaces in the generic, nonreversible, sortable order.]
We do compose the URLs in the reversal order like http://domain.company.com/solution/schemas/2009-05-15 and add the “com” part of URL.
<TargetNamespace> =:
http://<Domain>.<Company>.com/<SolutionShortName>/<ProjectShortName>/<Version>
<Version> =:
<date>
[in YYYY-MM-DD format]
[TBD]We considered using the version in two formats. One format is like 1.0.0.1, the format used for the .NET assemblies. See http://msdn.microsoft.com/en-us/library/51ket42z.aspx . The second version format uses a date. Use the first one only if you want a strict versioning rules, and in this case you have to create some version approval procedure. We use here the date format.
  • All schemas in one project use the same target namespace. Schemas in one project with equal target namespace are differentiated by the root node names. Do not place the root node name inside the target namespace.
  • Use the project creating date for the first versions of all schemas inside project.
  • Use the current date for the second and next versions.
  • Create the new version only if the old one is published to production (test) environment. Do not create new versions inside development cycles.
  • Use the YYYY-MM-DD date format to make the names “sortable”. Do not use MM/DD/YY format.
For example, for the MyCompany.MyDomain.MySolution solution and the MyProject project the target namespace should be the http://mydomain.mycompany.com/mysolution/myproject/2009-05-15 for the first versions of all schemas, if this project was created in 2009-05-15.
6 BizTalk artifacts
6.1 Orchestrations, Schemas, Pipelines
Names of these artifacts appear together with BizTalk application name mostly everywhere. We don’t need to use composite names. Use simple names for the names.
Note: If you see one word in several places of the full name, consider this as a bad signal. Try to rethink the terms used in the names. I repeat this rule here, because exactly in the full names of orchestrations, schemas and pipelines you can frequently see repetitive words.
6.2 Maps
<Map> =:
<SourceSchema>_to_<DestinationSchema>[for one-to-one map]
<SourceSchema1>_and_<SourceSchema2>_to_<DestinationSchema>[for two-to-one map]
If it is possible do not change the schema names in the map name. If the map name is excessive long, cut the schema names, but use the same cut rule for all map names.
6.3 Ports
Ports are the primary artifacts of the BizTalk solution. But in contrast to orchestrations they are used through the BizTalk application boundaries in many places, that is why, we have to use the composite names for the ports like for assemblies.
<Port> =:
<Solution>.<PortShortName>
Do we need to separate one and two-way ports and send and receive ports, for example be “R_” or “SR_” prefixes? Do they mix up in lookups or in lists? No. And answer to the first question is “No”, do not use prefixes in the port names.
Do we have to use the transport/protocol qualifiers in the port names, like .FILE or .SOAP? No. One port could use several protocols. Moreover port is on the upper level architecture than transport. But for dynamic ports the transport name can be the main part of the port name.
Do we have to use message type in the port names, like .Request? No. One port could work with several message types. But frequently the message type can be used for the port name.
Try to understand the main purpose of the port and use it in the name. For example, link the port name with transport for dynamic port; or link the port name with the partner name, or with message type.
For example, MyCompany.MyDomain.MySolution.MyPartner.
Use the prefixes to differentiate the artifacts in the XLang expressions. These artifacts are not usual .NET objects. They are used in different language context and sometime they use different language syntax. Prefixes really help to work with these artifacts.
<MessageName> =:
msg_ + <ShortMessageType>
<VariableName> =:
var_ + <Name>
<CorrelationName> =:
cor_ + <Name>
<OrchestrationParameter> =:
par_ + <Name>
<RoleLink> =:
roleLink_ + <Name>
7.2 Orchestration artifact types
We can use one suffix the “_type” for all different types because different types are seen only in the different lists and never mixed. For instance, we can never see the port types together with message types.
<ArtifactType> =:
<ArtifactName> + “_type
<PortName> =:
<prefix> + <Name>
where
Send port
Receive port
Send-Receive
(Solicit-Response)
port
Receive-Send
(Request- Response) port
prefix
S_+
R_+
SR_+
RS_+
For example, S_ OrderAck.
Notes:
  • The Port shapes are the real names, the names of the .NET objects. We can’t use spaces inside.
  • In the Orchestration view there are generic lists “Ports” and “Port types” that’s why we have to distinguish the ports with different Communication directions and pattern.
7.4 Orchestration Workflow Shapes
Problems with orchestration shapes:
%u00b7 Shapes are too small to display long names (only 12-18 characters).
%u00b7 We have to “hover mouse over” shape or click shape to show Properties window to “understand” this shape, to understand what message it is processed.
Useful features:
%u00b7 Feel free to use the same names for different shapes and use spaces inside the shape names. Shape names are not the “real programming names”. In reality they are the descriptions (excluding the Port shapes names); they are used only for description and for nothing more.
%u00b7 Icons on shapes give us the useful information. Do not repeat the “icon information” by words. For example, if we change a name of Construction shape from “Construct Input message” to “Input message” we get more clear definition because we have the Construct icon + name.
%u00b7 Shape names are used only in Orchestration Editor (excluding the Port shapes names). We don’t have to force any rules to make the “well-sorted” names (it’s the main purpose of the prefixes).
%u00b7 Use a Group shape to add description to a group of related workflow shapes.Group shape will display as much text as you want. Group shapes add a lot of documentation value to the orchestration.
7.4.1 Rules for shapes
Purpose of the orchestration and the most of the shapes is in processing the messages. We can unambiguously describe the messages by the message type. That is why in the most cases using the message type names gives us the main information about this message. That is why in the most cases using the message type names as the shape names gives us the main information about this shape, about message flow, about whole orchestration processing. Send shape with name “OrderAck” means … exactly!
%u00b7 Whenever it is possible use the MessageType of the processed message as a shape name.
%u00b7 Do not repeat the type of shape icon by word.
%u00b7 Do not repeat words from external shape name into the internal, nested shape name.
%u00b7 Feel free to use spaces inside the shape names.
%u00b7 Feel free to repeat the shape names.
7.4.2 Rules for specific shapes
Construct, Receive, and Send:
= name of the processed message without “msg_” prefix.
For example, [OrderAck]
Note: it’s easy to set and maintain this name: just copy part of it from Properties/Messages Constructed to Properties/Name. For example, from “msg_OrderAck” copy “OrderAck”
Transform:
= “from “ + name of the Source message
For example, [from OrderAck]
Note: it’s easy to set and maintain this name: just copy it (or part of it) from Properties/Input Messages to Properties/Name. For example: From “msg_OrderAck” copy “OrderAck”
Assignment:
No strict rules, only advice:
Name it like the methods in classes. But cut a verb if it possible. Use “set” and “get” if it possible.
For example, [set OrderAck]
Consider this chapter as “out-of-scope”. I placed it here because we discussed the folder names here. The files placement is a separate and wealthy topic. Here are only main considerations.
* If the project is simple, place all files in one project.
* If we want to use some files for references from other projects, place these files in separate project.
* Place artifacts to different projects if these artifacts have different refactoring lifecycle. For example, the Niem standard schemas are never changed then place them to the separate project. The maps are changed more frequently than schemas and we could place schemas and maps to the separate projects.
* Don’t place the technology-specific schemas and maps away from the orchestration they used for. For example, for the SQL port we generate a (technology) schema and usually create the map to transform the original schema to this (technology) schema. Place these schema and map together with orchestration, not into the Schemas/Maps projects.
In the BizTalk project folder add the subfolder the Tests. Use it to the unit tests. Inside the Tests create subfolders: In, Out, TestMessages.
For the BizTalk project with different artifact files you can add the solution folders the Schemas, Orchestrations, and Maps in case you have several schemas, orchestrations, and maps there.
9 Out of scope
Several BizTalk artifacts are out of scope this naming convention:
%u00b7 BRE artifacts: Rule sets, Vocabularies, etc.
%u00b7 BAM artifacts: Activities, Views, BAM Definitions, Tracking Profiles
%u00b7 Parties, Role links
%u00b7 Itineraries from the ESB Toolkit 2.0. I think the ESB Toolkit is a part of BizTalk 2009, because it is delivered in binary format, supported by Microsoft, has a lot of tooling, including Itinerary Designer.
See also
2. URL in Wikipedia [ http://en.wikipedia.org/wiki/URL ].


Appendix
Syntax
<Word> =:
[A-Za-z1-0]*
<CompositeWord> =:
<Word>.<Word>[.<Word>]
<ShortName> :=
<Word>
<CompositeWord>
<{Any}ShortName> =: <ShortName>
[replace {Any} with any term. For example, term Solutioncreatesa<SolutionShortName> term]
<Company> =: <ShortName>
<Domain> =: <ShortName>
<Solution> =:
<Company>.<Domain>.<SolutionShortName>
<ApplicationName> =: <Solution>
<AssemblyName> =: <Project>
<Namespace> =: <Project>
<SolutionsRootFolder> =: c:\Solutions
<SolutionFolder> =:
<SolutionsRootFolder>\<Solution>
<Project> =:
<Solution>.<ProjectShortName>
<ProjectFolder> =:
<SolutionFolder>\<ProjectShortName>
<TargetNamespace> =:
http://<Domain>.<Company>.com/<SolutionShortName>/<ProjectShortName>/<Version>
<Version> =:
<date>
[in YYYY-MM-DD format]
<Port> =:
<Solution>.<PortShortName>
<Map> =:
<SourceSchemaShortName>_to_<DestinationSchemaShortName>[for one-to-one map]
<SourceSchemaShortName1>_and_<SourceSchemaShortName2>_to_<DestinationSchemaShortName>[for two-to-one map]
Instructions
Keep the names of some BizTalk artifacts in the lists, a list per solution. Create, at last, a list of the target namespaces of all schemas. Keeping them in one list forces developers to use naming convention, because inconsistencies in the names are visible inside these lists on the development stage.
1. Create a new name in the list below.
2. Copy it to the name property of the new BizTalk artifact.
Target Namespace List
Port List

Finally! Connected OCS 2007 R2 to Trixbox (Asterisk) to a PSTN/PBX

I’ve been through many integration projects and I think now I’ve found a product more
complicated than BizTalk.

For the last 6 weeks internally we’ve been ’rolling out’ (more like dragging through
the mud) an OCS/UM setup – it now finally works!!!! (Inbound/outbound and UM Voicemail).

OCS – goes from 1 sever to 3!

In this post I’ll aim to take you through linking a working OCS system to a Trixbox
connected to MyNetFone (SIP Trunk provider). After countless weeks, forum posts and
beyond weird error messages – I’ll simplify it for you.

Me – no OCS, SIP, Trunk, Asterisk expert – great developer, can look at network packets
if I *really* have to.

I’m assuming you have OCS setup for IM and A/V between Communicator clients. The OCS
Mediation Server is where we are going to focus a little bit also.

Ok – what I wanted to dothis sounds simple.

The Aim:

  1. OCS (Mediation Server) connecting to my Virtual PBX ’PSTN’ so phone calls
    can go inbound and outbound.

  2. Create SIP Trunk ’connection’ to our SIP Trunk ’provider’ – in our
    case MyNetFone.
    SIP Trunks are similar to regular VOIP Accts, but a trunk allows you to have multiple
    voip numbers running over it. Similar to Proxy Servers for ’http’ connections.

    Generally speaking the SIP Trunks going externally need some form of authentication
    with the external SIP Trunk provider. This can come in many forms from username/pass,
    to special ’secrets’ being passed in certain packets.

    This took me some time to get right.

  3. Each user will be assigned a phone number (from the SIP Trunk) and all devices/phones/users
    will be managed by OCS.

The Problem(s):

  1. OCS talks SIP/TCP and ’the rest of the world’ talks SIP/UDP. Some
    translator is needed here – raging debates about this, but essentially we’re dealing
    with the last 40 odd years of the evolution of telephony systems.

    In short – get Trixbox
    2.8
    based on Asterisk 1.6 this DOES the translation.
    (Trixbox performs a huge array of functions, but with OCS in place we really
    need it only to do about 5% of it’s feature set – hence alot of the menu items we
    needed worry about)

  2. The bits you’ll need before you start:

    1. IP:X = IP address of your Mediation Server (if your server has multiple
      IP Addresses select the IP Addr that will be sending out (eventually) your Trixbox

    2. IP:Y = IP address of your new Trixbox Server (to install)

    3. External SIP Trunk Details (or VOIP acct details)

    4. OCS 2007 R2 Resource Kit Tools installed on the Mediation Server – http://www.microsoft.com/downloads/details.aspx?familyid=9E79A236-C0DF-4A72-ABA6-9A9602A93ED0&displaylang=en

      – great log analyser tool called snooper.exe

    5. Putty.exe – this allows you to ’rdp’ onto your new Trixbox (as this
      is a linux box)
      http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
  3. Installing Trixbox
    This piece is pretty simple – for our test case I installed this onto a Virtual
    Machine (in practice it’s generally advisable to install this on a physical machine,
    as the trixbox needs to use codecs and encode/decode which a typically time dependent)

    It’s an ISO so install it as you would any other ISO – it in a unix box but don’t
    be nervous, the Trixbox guys have put a great web interface over alot of the underlying
    stuff.

    Important to note:
    Seeing Trixbox is open source and is based on another product called ’Asterisk’,
    which in turn has components such as FreePBX and others, sometimes reference material
    for FreePBX may be applicable to your Trixbox.


    NOTE: I called my trixbox = xlator

    Installation Complete:
    Once initial installation is complete (if installing to a VHD the size is
    around 6GB), you should be able to go a browser and do:

    (at some point you’ll probably want to change your ’root’ password and also a user
    called ’maint’ which is used in the webinterface to perform admin tasks)

    http://xlator (the default install will also setup https://xlator for
    you)

    As shown, we’re interested in switching to ’maintenance mode’ clicking switch in the
    top left hand corner.

  4. Configuring the Trixbox environment

    1. As I mentioned earlier, we’ll only use about 5% of what Trixbox does. There’s some
      really key areas to make sure are setup and I’ll show you what they are.

    2. Turning on SIP/TCP capabilities for Asterisk
      Currently this isn’t a web interface checkbox, we need to modify a file called sip_general_custom.conf found
      in the /etc/asterisk directory.

      (the web interface has web config editor which we’ll use later with so many config
      files we can edit, *unfortunately* SIP.CONF isn’t one of them.

      1. Fire up Putty.exe (from your windows client) and type the address of your Trixbox in

      2. and
        hit OK, (you may be asked to OK a Security Token with the remote machine – part of
        SSH, just OK that)

      3. Login with root and the password you setup during the install. (welcome
        to the world of command lines – brings back the uni days, grep, ls, chmod. gee how
        I missed it)

      4. cd to the /etc/asterisk directory as follows

      5. Type nano sip_general_custom.conf and add the following lines:

      6. Press Ctrl-X then Y then press return to
        complete the save (pretty simple here really)

      7. Type cd /root to return back to your home directory.

      8. Listen to Asterisk with the Command Line Interface. This is sort
        of the interactive debugger in Asterisk.

        type asterisk -r

        this will show you what asterisk is doing when it receives calls and trys
        to dial them out.

        sip set debug on – lets you see what’s happening with SIP packets.
        sip set debug off – turns if off.

        *** VERY VERY HANDY when trying to establish connectivity ***

      9. (another folder of interest is the LOGS directory /var/log/asterisk – handy to keep
        in mind, but the web interface lets you see the logs)
    3. Add your OCS ’Connection’ or SIP TRUNK

      1. From the Admin Web Interface select PBX Settings (this and PBX
        Status
        are the 2 main areas we’ll go into)

      2. On the next page under Basic (on the LHS Menu) select Trunks

      3. Select Add Trunk -> Sip Trunk and fill in as follows:

      4. Leave everything blank or default except for the following sections:

      5. Key information above:

        1. Trunk Name – Connect-with-OCS. This name is used later to basically
          ’route’ incoming calls from our ’external’ SIP trunk to internal. (you can call it
          your own name if you like – just keep things simple)

        2. context=from-Super-OCS. In all my troubles, contexts in Asterisk
          are the solution. This I set so that it won’t conflict with any other ’system’ contexts
          (e.g. from-pstn, from-internal).

          When a call is received via the trunk, in our case from OCS mediation server sending
          out, Asterisk will associate a context with it (if not, you’ll get ’received number
          from an unknown peer’)

          The key here is that we will create a section in a config file that will allow
          us to define *exactly* what happens around this context.
          (this piece took
          another week)

        3. host=10.1.1.30 – this should be the IP Address of YOUR MEDIATION server. Asterisk
          will use the IP address of the incoming SIP request to try and associate it to a context,
          without this entry, your request will come from unknown.

        4. Inbound/Outbound – inbound messages are messages received at
          Trixbox FROM OCS. Outbound Messages are messages send to OCS FROM Asterisk.
          They
          are then given a context and any other details needed.
      6. Save the above configuration by going to the bottom of the page and clicking Submit
        Changes
        .

      7. You should have your first Trunk (don’t apply changes yet, we’re creating another
        Trunk)

      8. Notice these names above (I’ve got the 2nd one added too, you’ll have 1 at this point)

        Later we will ’Dial’ calls out to these trunks with syntax like:
        Dial(SIP/<the number/extension>@Connect-with-OCS)


        (took me 2 days to find that gem)

    4. Creating your External Trunk – MyNetFone (in my case)
      This is where alot of the magic happens for the REGISTER SIP packets – if
      you have trouble with your external provider, sit with SIP SET DEBUG ON in the ’asterisk
      -r’ interface in the PUTTY app to try and make heads or tails of it.

      Also you can see failures in the logs and your SIP Trunk won’t be registered in the
      PBX Status screen.

      1. Click on Add Trunk -> SIP Trunk

      2. Fill it in as follows (for MyNetFone) (took me a bit of trial and
        error)

        1. General Settings

          1. Outbound CallerID: “61555555555” <sip:61555555555@<your
            public IP>

            the 6155 number *should* be replaced with your own number allocated to your
            TRUNK.

            Your public IP is potentially NAT-ed from your Trixbox to the outside world. The web
            admin
            will show you your Public IP in the Top RH Corner.

          2. Never Override CallerID=checked

            (I’m currently still playing with this setting, but this works for now)
        2. Rest defaults until

        3. Outgoing Settings

          1. Trunk Name=MyNetFone (important to remember your name)

          2. PEER DETAILS

              disallow=all
              allow=alaw&ulaw
              authname=61555555555

              canreinvite=yes
              dtmfmode=rfc2833
              host=sip20.mynetfone.com.au
              insecure=very
              nat=yes
              pedantic=no
              qualify=yes
              type=peer
              username=61555555555

              fromdomain=sip20.mynetfone.com.au
              context=from-MyNetFone

            1. Note the context=from-MyNetFone which is one of the most important
              things here.

              Also the ’canreinvite=true’

              Note: 61555555555= should be replaced with <your user name or phone
              number>

            2. In honesty this section took me about a week to work out – nat on, off?? tweaks here
              and there. You’ll see other posts that include ’secret=’.
              My setup didn’t require this.
          3. Incoming Settings

            1. User Context=from-MyNetFone

            2. USER DETAILS

                canreinvite=yes
                fromuser=61555555555

                insecure=very
                qualify=no
                type=peer
                username=61555555555

                host=sip20.mynetfone.com.au
                context=from-MyNetFone

                 

              Note: 61555555555= should be replaced with <your user name or phone
              number>

          4. Registration

            1. Register String = 61555555555
              @sip20.mynetfone.com.au/61555555555>

        4. Click Submit Changes to save your work.

        5. Click Apply Changes to apply changes

        6. You may get a warning – continue with Reload.
    5. Well done – at this point we’ve setup 2 trunks and we now need to ’route’ calls between
      the two.

      Trawling the forums, if you set the context to from-internal any
      call received on the Trunk, Asterisk will examine all other trunks for a possible
      match. Let’s not confuse the issue right now 🙂

    6. Let’s Config OCS Mediation at this point – we can really do this
      any time, but the screen shots I’m showing you shortly will have OCS Mediation plugged
      in. So let’s do it.

      1. Jump onto your OCS Mediation Server and open up the OCS Server
        Admin tool
        as follows:

      2. Points to Note here: we’re interested in the next hop settings.

      3. Right Click on your Mediation Server and select Properties.

      4. Configure as follows:

      5. Under PSTN Gateway next hop – the address: xlator

        (you should have internal DNS resolution to your trixbox)

      6. Click OK and restart the Mediation Service (right
        click on the server and select stop, then start)

      7. Let’s flick back to the Web Admin of the Trixbox to see how things are going.
    7. Check that all things are setup and working – mainly your Registrations.

      1. The Web Admin in Trixbox gives a detailed view of what’s going on, also your Putty.exe
        session should be chatting away nicely – what it means, is another story!

      2. From the Web Admin -> PBX -> PBX Status to see something like

      3.  
        The Key areas that you need to keep an eye on are:

        1. SIP Peers – make sure that under Hosts there are
          no Unknown(s), as call routing won’t work the way I’ve outlined.

        2. Our connection with OCS doesn’t need to be registered.

        3. Our External Registration *should* be Registered by now – if not,
          go back to your trunk and configure the Outbound Settings and the Register String
          at the bottom of that page. ** DON’T MOVE ON UNTIL THIS IS COMPLETE **
      4. If you’ve set your dialing rules up in OCS on the Mediation Side, you should
        be able to dial a number and see activity in the Trixbox logs
        and in your
        Putty Terminal.

      5. Almost there..

    8. Setting up Call Routing between our two worlds.
      At this point we could setup a bunch of extensions, inbound routes, outbound
      routes etc – and I did do that the first time through (10 users, 10 numbers, inbound
      routes etc etc – just pain).

      I thought there’s got to be a better way and here something that took 1 week to figure
      out – Trixbox forums are a great place to start with all of this, but they tend to
      be focused around building Trixbox out as the ’OCS equivalent’, setting up receptionists,
      etc etc. I found I was spinning my wheels alot here, make a tweak, doesn’t work, read
      the forum, make another change, go back and redo a change etc.

      Here’s the simplest solution I’ve found: (for the code syntax – this
      was a great place to start
      )

      1. From the Web Admin select PBX -> Config File Editor and
        select extensions_custom.conf

      2. (you will have to scroll down this list, but it’s there)

      3. Scroll to the bottom of this file until you find the line
        #include extensions-away-status.conf

      4. Insert this code above that line.

        1. Setup OCS/Communicator clients Dialling OUT

            [from-Super-OCS]
            exten => _X.,1,Answer
            exten => _X.,2,Dial(SIP/${EXTEN}@MyNetFone,,tr)

          1. What does this do??? yeah good questionhad to ask myself that as
            well.

            Ok – hopefully you recognise the from-Super-OCS text in []. Remember
            from our OCS Trunk, anything that Asterisk/Trixbox receives FROM OCS via that Trunk
            was associated with this Context.

            So what we’re saying here is that “If you have a message from from-Super-OCS do
            the following steps”

            1. exten => _X.,1,Answer

              exten = something to do with when Asterisk goes searching for the
              right extension that matches the one that it has been given.

              _X. = saw this on a few other config files, it’s part of a dialing
              plan, X=any digit, . = any number of following digits.

              This will match *all* numbers dialled.

              _ = no idea (maybe some pattern match)

              ,1 = believe it or not, this is how we say “run me 1st”

              Answer = predefined function or application that will pickup the
              call. We can then work out what to do with the call.

            2. exten => _X.,2,Dial(SIP/${EXTEN}@MyNetFone,,tr)

              _X. = match all numbers.

              ,2 = run me 2nd

              Dial(SIP/${EXTEN}@MyNetFone,,tr)
              =
              here we’re dialling a SIP trunk – called SIP/MyNetFone. Later if you look
              at your SIP TRUNKS page, you’ll see your Trunks listed this way.

              What I wanted was SIP/<number to dial>@<outgoing trunk name>

              ${EXTEN} = variable that holds the ’extension’ dialled from the communicator
              client. This is the phone number.

              NOTE: sometimes parties at the other end of the trunk want a certain dial
              prefix
              e.g. +61
              you could use something like:
              Dial(SIP/+61${EXTEN}@MyNetFone)

              The ‘+61’ & ${EXTEN} get appended together in the above line.

              ,,tr = something to do with allowing the calls to be transferred.

              I originally didn’t have this, and my inbound calls to OCS worked, then when I tried
              to transfer them the Exchange UM Voicemail, they hung up.

              I added this in for inbound and Exchange Voicemail worked, so I figured it can’t hurt
              for outgoing.

              How fiddley is all this stuff!!!

        2. Setup External Calls Coming to OCS

          According to my OCS Expert buddy Dan, our internal OCS setup is such that
          all extensions have a +61 appended to them. the ’+’ in ’+61’.

          Checking on the ’asterisk -r’ interface, MyNetFone will pass 02 and not +612. So
          I needed to do a little tweaking of these numbers.

          Here’s the result 🙂

          1. Below the code you’ve added above add this.

            [from-MyNetFone]
            exten => _0X.,1,Set(numDialled=+61${EXTEN:1})   ;get all but the first
            digit from the Extension dialled.
            exten => _0X.,2,Set(__FROM_DID=${EXTEN})       ;sets
            a global variable.
            exten => _0X.,3,Answer
            exten => _0X.,4,Dial(SIP/${numDialled}@Connect-with-OCS,,tr)

            exten => _X.,1,Set(numDialled=+61${EXTEN})

            exten => _X.,2,Set(__FROM_DID=${EXTEN})
            exten => _X.,3,Answer
            exten => _X.,4,Dial(SIP/${numDialled}@Connect-with-OCS,,tr)

            Note: firstly from-MyNetFone in the above code,
            once again this is the context from our corresponding Trunk.

            exten=> _0X.,1,Set() = the _0X. here will match all the numbers passed to us from
            MyNetFone with a ’0’ at the front.
            e.g. 02 – so I need to strip the ’0’ off and add +61(0)2

            Here I created a local variable called ’numDialled’ to hold the translated
            number. You can see the ’+61’ added to ${EXTEN:1}.

            ${EXTEN:1} = give me all numbers except the first.

             

        3. Your file should look like this now:

            [from-Super-OCS]
            exten => _X.,1,Answer
            exten => _X.,2,Dial(SIP/${EXTEN}@MyNetFone,,tr)

            [from-MyNetFone]
            exten => _0X.,1,Set(numDialled=+61${EXTEN:1})   ;get all but the first
            digit from the Extension dialled.
            exten => _0X.,2,Set(__FROM_DID=${EXTEN})       ;sets
            a global variable.
            exten => _0X.,3,Answer
            exten => _0X.,4,Dial(SIP/${numDialled}@Connect-with-OCS,,tr)

            exten => _X.,1,Set(numDialled=+61${EXTEN})

            exten => _X.,2,Set(__FROM_DID=${EXTEN})
            exten => _X.,3,Answer
            exten => _X.,4,Dial(SIP/${numDialled}@Connect-with-OCS)

            #include extensions-away-status.conf

        4. >

        5. Click on Update to save the file.

        6. Click on ReRead Configs from the top menu. You may need to scroll
          to the top.

        7. You’re Asterisk/Trixbox is ready to go!

        8. >

        9. What Successful Calls Look like here: (you can get these from your
          Putty session, running ’asterisk -r’

          1. OCS client going OUT

            1. I’ve scrubbed the actual number dialled, but you can see where the number appears,
              the fact we Answer, and then Dial.

              Also where the ’Contexts’ appear.

          2. Inbound to OCS

        10. >
          >>

           

           

           In conclusion:

          Hopefully this will help unravel the huge mystery on how to connect these
          systems together. There’s many other ways this can be achieved, and I’d love to say
          it’s the silver bullet for this, but there’s just so many factors in your solutions.

          This should certainly get you a large step down that path.

          Good luck.

          Mick.

ASP.NET MVC V2 Preview 1 Released

ASP.NET MVC V2 Preview 1 Released

The ASP.NET team just released the first public preview of ASP.NET MVC Version 2.  You can download it here.

Today’s preview works with .NET 3.5 SP1 and VS 2008, and can be installed side-by-side on the same machine as ASP.NET MVC 1.0 (meaning they don’t conflict and your existing ASP.NET MVC 1.0 projects will not be impacted if you install it).  If you have both ASP.NET MVC 1.0 and ASP.NET MVC 2.0 installed you’ll see two ASP.NET MVC project templates within Visual Studio 2008’s “New Project” dialog:

The release notes that come with the ASP.NET MVC 2 Preview release detail how to upgrade existing ASP.NET MVC 1.0 projects to use V2 if you’d like to migrate them forward to take advantage of the new features.

New Features

ASP.NET MVC V2 will include a bunch of new capabilities and features (some of these have already been called out on the ASP.NET MVC roadmap page).  Today’s “Preview 1” release contains a first look at some of the new features.  Many more features will show up in future preview builds.  The Preview 1 bits are still relatively early – the team is releasing today’s build to start receiving and incorporating feedback. 

Below are some quick details about some of the new Preview 1 capabilities:

Areas Support

ASP.NET MVC 2 includes support for a new feature called “areas” that allow you to more easily partition and group functionality across an MVC application.

Areas provide a means of grouping controllers and views to allow building subsections of a large application in relative isolation to other sections. Each area can be implemented as a separate ASP.NET MVC project which can then be referenced by the main application. This helps manage the complexity when building a large application and facilitates multiple teams working together on a single application together.

Below is a screen-shot that shows a single solution that has three projects.  One of the projects is named “CompanySite” and includes the core site content, layout and controllers and views. There are then two separate “Area” projects – “Blogs” and “Forums”.  These projects implement the functionality that exists under the /Blogs and /Forums URL sections of the site – and encapsulate all of the routing rules, controllers and views implementing these sections:

The Preview 1 release includes the first part of the areas feature implementation.  It doesn’t include any tool support yet (right now you need to manually add a build task to create an area project and set it up).  Future preview releases will include tooling support, and expand and refine the feature-set further.

DataAnnotation Validation Support

ASP.NET MVC 2 now includes built-in support for the DataAnnotation validation support that first shipped with .NET 3.5 SP1 – and which is used with ASP.NET Dynamic Data and .NET RIA Services.  DataAnnotations provides an easy way to declaratively add validation rules to Model and ViewModel classes within an application, and have automatic binding and UI helper validation support within ASP.NET MVC.

To see this feature in action, we can create a new “Customer” ViewModel class like below that has five properties on it (implemented using the C# automatic property feature).

We can then decorate the properties with appropriate validation rules using the DataAnnotation attributes implemented within the System.ComponentModel.DataAnnotations namespace.  The code below uses 4 different built-in validation rules – [Required], [StringLength], [Range], and [RegularExpression].  The namespace also includes a base class (ValidationAttribute) that you can subclass to create your own custom validation attributes.

We can then create a CustomersController class that has two Create action methods on it.  The first Create action method handles HTTP GET requests to the “/Customers/Create” URL, and renders a view template based on an empty Customer object.  The second Create action method handles HTTP POST requests to the same URL (and takes a Customer object as a method parameter).  It checks if there are any model binding errors to the input submitted, and if there are errors it redisplays the view template using the already entered data.  If there are no errors it displays a success view to the user:

Finally, we can right-click within either of the Create action methods above, choose the “Add View” context menu command, and automatically “scaffold” a “create” view template that is based on the Customer object.  When we do this the generated scaffolded view template will contain the below HTML <form> for our Customer:

And now when we request the “/Customers/Create” URL in our browser we’ll get an initial empty form like below:

If we enter invalid input and perform a post to the server, the ASP.NET MVC 2 model binder will detect that there are DataAnnotations attributes on our Customer class, and automatically validate the posted form input using them.  If there are errors our controller action method redisplays the form – which will cause the appropriate validation error messages to be rendered to the user like below.  Note how the validation property error message strings we specified using the DataAnnotation attributes are displayed to the user by the Html.Validation helper methods.  No extra code is required to enable this.

The above form will redisplay with error messages each time the user enters invalid input and attempts to perform a form post.

In a future ASP.NET MVC 2 preview we are planning to ship the jQuery Validation plugin as part of the default project template, and add support for the automatic client-side JavaScript enforcement of DataAnnotation validation rules as well.  This will enable developers to easily add validation rules in one place on either a Model or ViewModel object, and have them be enforced both client and server-side everywhere it is used within the application.

If you do not wish to annotate your model or viewmodel classes directly, you can alternatively create a “buddy class” that accompanies your model class and encapsulates the DataAnnotaton rules separately.  This capability is also useful for scenarios where VS is code-generating/updating the properties on a class directly and you cannot easily add attributes to the generated code (for example: classes generated by the LINQ to SQL or LINQ to Entities designers). 

In addition to providing built-in support for DataAnnotations, the DefaultModelBinder class in ASP.NET MVC V2 now has new virtual methods that can be overridden to easily integrate other validation frameworks as well (for example: Castle Validator, EntLib Validation, etc).  The validation UI helper methods in ASP.NET MVC are designed to support any type of validation framework (they have no direct knowledge of DataAnnotations).

Strongly Typed UI Helpers

ASP.NET MVC V2 includes new HTML UI helpers that enable you to use strong-typed lambda expressions when referencing the view template’s model object.  This enables better compile-time checking of views (so that bugs can be found at build-time as opposed to runtime), and also enables better code intellisense support within view templates.

You can see an example of the better intellisense in action below – notice how I am getting a full listing of the customer model object’s properties when using the new Html.EditorFor() helper method:

Preview 1 has built-in support for new Html.EditorFor(), Html.LabelFor(), and Html.DisplayFor() helpers.  An updated MVC futures assembly that we are shipping this week adds additional Html.TextBoxFor(), Html.TextAreaFor(), Html.DropDownListFor(), Html.HiddenFor(), and Html.ValidationMessageFor() helper methods as well (overtime these will move into the core ASP.NET MVC 2 assembly too).

Below you can see an updated version of the “create” view template for our customer creation scenario.  Notice how instead of using string expressions to reference the customer object we are instead using strongly-typed lambda expressions with the UI helpers.  We can get full intellisense and compile-time checking with all of them:

The Html.LabelFor() helper method above generates <label for="Name">Name:</label> HTML markup.

The Html.EditorFor() helper method can be used for any datatype value.  By default it is smart and will output an appropriate HTML <input/> element based on the type to be edited.  For example, it will generate <input type=”text”/> elements for the first four properties above (which are strings and integers).  It will generate a <input type=”checkbox”/> element for the final “IsActive” property – which is of type boolean.

In addition to supporting simple data-types, the Html.EditorFor() helper method also allows you to pass more complex objects with multiple properties to it.  By default it will loop over the public properties of the object and generate a <label>, <input/> element, and any appropriate validation message for each property it finds.  For example, we could re-write the above view to have just a single Html.EditorFor() call for the Customer object to conceptually output the same markup as above:

The strongly typed helpers allow you to optionally decorate the properties of the Customer ViewModel class with [DisplayName] attributes to control the label string that is output for each property used (for example: instead of having a label text of “IsActive” we could apply a [DisplayName(“Is Active Customer:”)] attribute). 

You can also add [ScaffoldColumn(false)] attributes to indicate that a particular property shouldn’t be rendered at all in scenarios like above where complex objects are passed to Html.EditorFor().

UI Helper Templating Support

The Html.EditorFor() and Html.DisplayFor() helper methods have built-in support for rendering both standard data-types as well as complex objects with multiple properties.  As noted above, they also support basic customization of rendering by applying attributes like [DisplayName] and [ScaffoldColumn] to the ViewModel.

Often developers want to be able to customize the output from UI helpers even further, though, and have total control over what is generated.  The Html.EditorFor() and Html.DisplayFor() helper methods support this via a templating mechanism that allows you to define external templates that can override and completely control the output rendered.  Better yet, you can customize the content rendered on a per-datatype/class basis.

With Preview 1 you can now optionally add an “EditorTemplates” and/or “DisplayTemplates” folder underneath either a \Views\[controllername] directory (if you want to customize the rendering for views used by a specific controller) or underneath the \Views\Shared folder (if you want to customize the rendering for all views and controllers in an application). 

You can then add partial template files to these folders to customize the output rendering performed on an individual datatype and/or class basis.  For example, below I have added an EditorTemplates folder underneath the \Views\Shared folder – and added three custom template files to it:

The “Customer.ascx” template above indicates that I want to customize the output anytime Html.EditorFor() is passed a Customer object (for example: I could customize the exact ordering/layout of the Customer properties).  The “DateTime.ascx” template above indicates that I want to customize the output anytime Html.EditorFor() is passed a DateTime property (for example: I might want to use a JavaScript datepicker instead of a plain textbox).  I could optionally add an “Object.ascx” template to the folder if I wanted to override the default rendering of all objects.

In addition to customizing rendering on a per-type basis, you can also add “named templates” to the folder.  A common scenario might be a “CountryDropDown” template that handles a string datatype – but instead of providing a standard textbox instead renders a <select> dropdownlist of country values that a user can pick from.  Below is what this editor template might look like:

We can explicitly indicate that we want to use the above template by passing its name as an argument when we invoke the Html.EditorFor() helper method.  For example, below in addition to specifying a lambda expression for our Country property, we are also specifying the name of the editor template to use when rendering it:

Alternatively, you can specify “UIHint” attributes on your ViewModel properties and types.  This allows you to indicate the default editor or display template to use in a single place, and have it be used in all views across your application (without having to explicitly pass it as an argument to Html.EditorFor). 

Below is an example of how to indicate using a UIHint attribute that the Customer.Country property (which is of type string) should by default use the CountryDropDown template when being rendered:

Once we set the above attribute on our ViewModel we no longer need to specify a template name explicitly when we use that property with Html.EditorFor().  And now when we hit refresh on our /Customers/Create URL our Country property will be rendered as a dropdown instead of a standard textbox:

Other Cool Features

ASP.NET MVC 2 Preview 1 includes a number of other small, but really nice, feature additions.  A few of my favorites include:

New [HttpPost] Attribute

It is pretty common with ASP.NET MVC to split up the handling of a URL across two action methods – one that handles GET requests and one that handles POST requests.

With ASP.NET MVC 1 you used an [AcceptVerbs(HttpVerbs.Post)] attribute to indicate the “Post” version of an action method:

This still works with ASP.NET MVC 2. Alternatively, though, you can also now take advantage of a terser [HttpPost] attribute that does the same thing:

Default Parameter Values

Handling optional parameters is a pretty common web scenario.  With ASP.NET MVC 1 you could handle optional parameters either by registering a custom routing rule and specifying a default value with it, or by marking an action method parameter as nullable and then adding code within your action method to handle whether it was null (and if so provide a default value).

ASP.NET MVC 2 Preview 1 now supports decorating action method parameters with the DefaultValueAttribute from the System.ComponentModel namespace.  This allows you to specify a parameter value that ASP.NET MVC should pass in if it is not present as part of the request.  For example, below is an example of how we could handle both the /Products/Browse/Beverages and /Products/Browse/Beverages?page=2 URLs – and have the “page” parameter value be “1” if it isn’t provided as part of the querystring:

VB today allows you to specify default parameter values directly within the VB language (avoiding the need to explicitly specify the DefaultValue attribute like above).  C# in VS2010 will also support default values with optional parameters – which will enable you to rewrite the above code simply as:

This should make handling default/optional scenarios really easy and clean.

Binding Binary Data

ASP.NET MVC Preview 1 adds support for binding base64-encoded string values to properties of type byte[] and System.Data.Linq.Binary.  There are now two overloaded versions of Html.Hidden() that can take these data-types.  These can be useful for scenarios where you want to enable concurrency control within your application and want to roundtrip timestamp values of database rows within your forms. 

Summary

Click here to download a .zip file that contains a ASP.NET MVC 2 project that implements the sample code I demonstrated in the above walkthrough.

Today’s build of ASP.NET MVC 2 is just a first preview.  More features will be coming in future previews, and the team expects to get a lot of feedback on ways to improve and enhance the release. 

The goal with doing these regular previews is to help make sure that this feedback process is open and that anyone who wants to participate can easily get involved.  Please post any feedback, suggestions or problems you have to the ASP.NET MVC Forum on www.asp.net.  You can also learn more about the release from Phil Haack’s MVC2 post, and from the Channel9 video Phil did with Scott Hanselman about the Preview 1 release.

Hope this helps,

Scott

P.S. 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)

Service Virtualization and the Managed Services Engine (MSE)

Service Virtualization and the Managed Services Engine (MSE)

Over the past several months, I’ve spent a lot of time exploring the concept of service virtualization. Service virtualization is an emerging trend in the SOA landscape that focuses on providing a common infrastructure for building and managing a complex service ecosystem – the Managed Services Engine (MSE) brings service virtualization to life on the Microsoft platform. During my journey, I wrote three papers you might find helpful:

Why Service Virtualization Matters?

Four page executive summary on Service Virtualization

SOA Simplified: Service Virtualization With The Managed Services Engine

An article published in the May 2009 issue of MSDN Magazine

An Introduction to Service Virtualization on  the Microsoft .NET Platform

A 57 page whitepaper that is an in-depth extension of the MSDN Magazine article

In the end, service virtualization can help reduce your time-to-market for new investments on-premises or in the cloud and it will provide a more realistic approach to managing your service ecosystem as it grows over time – it can help you realize the full benefits SOA has to offer.

RESTful Services with ASP.NET MVC

RESTful Services with ASP.NET MVC

Although I spend most of my development focus on WCF, I’ve become more and more intrigued by the possibility of using ASP.NET MVC as another framework for building RESTful services – this is especially compelling when using XHTML for your resource representations.

In last month’s issue of MSDN Magazine, I was able to capture these ideas in an article titled RESTful Services with ASP.NET MVC. If you’re working with REST today, I’d be very interested to hear your thoughts on the ideas found in this article.

Check it out and let me know what you think, or better yet, connect with me on Twitter.

http://msdn.microsoft.com/en-us/magazine/dd943053.aspx

New “WCF Essentials” best practices series

Maybe you have decided WCF is the right technology for your next project because it has the power, productivity, and flexibility you need. But you might be a little nervous that your team will be able to get up to speed quickly and make the right design choices in applying WCF to you project.  Or maybe you just used WCF successfully for you last project, but wonder if there are things you could have done better.

Either way, you will want to check out the new series of articles that we are releasing to the WCF Dev Center called WCF Essentials.  The goal of this series is to give you “best practices” guidance on the big things to think about so you can apply WCF “correctly”.  We will be releasing this guidance as series of articles or ’chapters”, roughly one chapter every other week.

This series is written by Michele Bustamante from IDesign, who has been working with WCF and advising customers on how to apply it since the early beta.  Her book Learning WCF: A Hands-on Guide is one of the best resources around for learning WCF.  Michele also recorded a series of web casts that start with the basics and cover a broad range of WCF topics.

So this guidance is coming from a great source and has been reviewed by other WCF experts.  But we realize that “correctly” and “best practices” are subjective terms, so to encourage community feedback and discussion we will be starting a thread on the WCF Forum for each chapter.  Please use these forum threads to ask clarifying questions and to offer your own suggestions for best practices in each area.

Chapter 1 covers the basics and gives and overview of some of the topics that will be discussed in following chapters.  And be sure to participate in the forum discussion thread for this chapter.

New BizTalk 2009 courses available

New BizTalk 2009 courses available

I’m happy to announce that we have two new BizTalk 2009 courses available for instructor led training: BizTalk Server 2009 Fundamentals and SOA and BPM Fundamentals with BizTalk 2009. 

The BizTalk Server 2009 Fundamentals class is for .NET developers new to BizTalk who need a solid grounding in the messaging and orchestration capabilities of BizTalk.  It covers the messaging architecture, schemas, maps, adapters, routing, pub/sub etc. and the orchestration capabilities.  In addition, it provides coverage of using WCF to expose BizTalk as service endpoints, or to consume services from BizTalk solutions.  In this class, I took a slightly different approach from our traditional classes with the introduction of two hands-on projects during the course.  These projects provide students with real world challenges to solve without the step-by-step instructions of a lab manual.  Students in previous classes have really enjoyed these challenges and commented on how well they helped solidify the material. 

The SOA and BPM Fundamentals with BizTalk 2009 provides existing BizTalk developers with more in depth training on the capabilities of BizTalk Server and the ESB Toolkit when working with BPM and SOA solutions.  Like the other class, this one mixes lecture and labs with hands-on projects to help solidify the learning.  This course focuses on BPM capabilities such as the Business Rules Engine, BAM and the ESB Toolkit Portal as well as SOA topics including on/off ramp and itinerary processing in the ESB Toolkit and a deep dive on the WCF adapters. 

Talk to our sales staff to schedule on-site deliveries of either training, and look for the online version in your Pluralsight On-Demand! subscription in the fourth quarter of this year or first quarter of 2010.