BizTalk Server 2004: Generating C# source files

BizTalk Server 2004: Generating C# source files

Some time ago I published a utility on GotDotNet.com which dumps the temporary C# source code files generated by BizTalk during compilation. The utility works quite well, but cannot always dump all the files because it is unable to prevent BizTalk from deleting files once compilation is complete. BizTalk sometimes gets there first, removing the temporary files before the utility has a chance to copy them to the target dump location. Another problem is that the files have meaningless names, and are therefore difficult to trace back to the corresponding BizTalk artefacts.


The utility is cool…but quite unnecessary. It turns out that Microsoft has implemented an undocumented registry setting to control the generation of C# files. Create a key called BizTalkProject at the following location:



HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1


Next, create a DWORD value called GenerateCSFiles. Set the value to 1 (or higher). Restart Visual Studio, load a BizTalk project and re-compile. Now take a look at your project folder. Some of you may be disappointed to know that GenerateVBFiles and GenerateJSFiles are not supported.


Enjoy!

Diagnostic Tracing with BizTalk 2004

Diagnostic Tracing with BizTalk 2004

(Note – this work has been updated for log4net 1.2.9. See the ‘Tools’ download in
the Deployment
Framework
)

Early on when working with BizTalk 2004, it might be tempting to view the ability
to track orchestration events (and the use of the orchestration debugger) as a substitute
for traditional diagnostic logging.;

After all, the orchestration debugger can tell you exactly how far you got in an orchestration,
and what path through the workflow you took to get there

However, consider these limitations:

  • The orchestration debugger is used either a) after the orchestration has completed
    or b) in conjunction with a breakpoint.  Neither of these choices is ideal, and
    only the latter gives you visibility into the intermediate values of variables/messages.

  • Once an orchestration involves looping constructs, multiple orchestrations connected
    via messaging, etc. the orchestration debugger often loses quite a bit of diagnostic
    value.

Given this, it can be useful to integrate diagnostic logging into your orchestrations
and the components they call.  If we are going to invest in this effort, we’d
like to use something richer than the built-in System.Diagnostics.Trace/Debug infrastructure.

Log4net is an Apache-sponsored initiative
within the “Apache Logging Services
project.  It provides a rich diagnostic infrastructure for .NET, with support
for hierarchical logging and configuration, multiple logging targets, and support
for logging context.

A recent
article
outlined the advantages of log4net over Microsoft’s Enterprise Instrumentation
Framework (EIF), though Microsoft/Avanade will be revamping this logging infrastructure
with the release of the Enterprise
Template Library

Given that the log4net initiative has broad support at the API layer (i.e. log4j,
log4PLSQL, etc.) and platform layer (including .NET CF) as well as the benefit of
maturity, log4net seems like a very reasonable choice for instrumenting BizTalk 2004
applications.  (The Enterprise Template Library logging component will likely
be a good choice as well when released.)

Following is a discussion of log4net itself, along with what is required to use it
in a BizTalk 2004 setting.

Quick Insight into log4net 

Without diving immediately into the log4net API, let’s get a sense for what
it can do.  What do we mean by hierarchical logging and configuration with multiple
target support?

Suppose we have classes with these namespace-qualified names:

MyCompany.MyDepartment.MyClassA
MyCompany.MyDepartment.MyClassB

Each of these classes can obtain a logger specific to their class by declaring a static
member as such:

private static readonly ILog log = LogManager.GetLogger(typeof(Foo));

Each class (MyClassA/MyClassB) can now emit trace with statements such as log.Info(“hello
world”)
> or log.Warn(“a potential problem…”). 
Default log levels include: Debug, Info, Warn, Error, and Fatal (though these can
be expanded.) 

The concept of “context” can be added to a stream of trace messages via
NDC.Push(“some context”)/NDC.Pop or MDC.Set(“somekey”,”somevalue”). 
(These class names are short for “Nested Diagnostic Context” and “Mapped
Diagnostic Context” respectively.)  These can be extremely useful for multithreaded/multi-user
applications, to distinguish the streams of related trace messages from each other. 
This context can be optionally formatted into the associated tracing statements, as
will be shown shortly.

If we want to turn on tracing at the ‘Error’ level by default, at the
‘Warn’ level for MyCompany, and at the ‘Debug’ level for MyClassA,
we would simply configure as follows (notice the use of the namespace hierarchy):

<root>
   <level value="ERROR" />
</root>
<logger name="MyCompany">
   <level value="WARN" />
</logger>
<logger name="MyCompany.MyDepartment.MyClassA">
   <level value="DEBUG" />
</logger> 

This can be changed on-demand simply by changing the configuration file, which can
be reloaded automatically without restarting the application.  This allows us
to a) not be blinded by too much trace information and b) not impose undue server
load by tracing, whereas a non-hierarchical approach only allows for one logging level
for an entire application. 

Suppose it is desired to route all trace information (by default) to OutputDebugString,
where a utility such as dbmon.exe or DebugView can
be used to view it.  Suppose further it is desired to prefix our output with
the date, thread Id, logging level, the name of the logger (i.e. MyCompany.MyDepartment.MyClassA),
and the current context.  To do this with log4net, we would have our configuration
file declare an “appender” of the appropriate type, and include a declaration
of a “layout” as follows.  The “appender” is then referenced
by a particular logger (or the root logger).

<appender name="OutputDebugStringAppender" type="log4net.Appender.OutputDebugStringAppender"
>
   <layout type="log4net.Layout.PatternLayout">
      <!-- The format specifiers let us add a wide variety
of additional info -->
      <param name="ConversionPattern" value="%d [%t] %-5p %c
[%x] - %m%n" />        
   </layout>
</appender>
<root>
   <level value="ERROR" />
   <appender-ref ref="OutputDebugStringAppender" />
</root> 

This might yield trace output as follows:

16:39:33,022 [316] INFO  MyCompany.MyDepartment.MyClassA [SomeContext]
- Hello World

Again, the specifics of what additional information can be included in trace output
can all be configured dynamically at runtime.  Note that other useful information
such as method name, file name, line number, caller’s window identity can all
be added with the PatternLayout class as well, though it is quite expensive (further
adding value to the hierarchy concept!) 

Moreover, each element of the hierarchy can be directed to a different appender, or
to multiple appenders.  Built in appenders include support for ADO.NET, .NET
remoting, SMTP, files, rolling files, buffering, and the Event Log (among others.) 
Because the Event Log is supported, there is no need to use a separate API to support
such logging. 

Core log4net Concepts 

Without attempting to present a full tutorial (see this
introduction
for a more complete discussion), the core concepts in log4net include: 

Loggers: Use by code to emit trace output at various levels.

  • Loggers are organized into hierarchies just like .NET namespaces (they don’t have
    to correspond, but often should.)  Example: System is parent of System.Text,
    and an ancestor of System.Text.StringBuilder. 

    • It is typical to have the logger name equal to a fully-qualified class name. 
  • Loggers are retrieved using a static method of LogManager, e.g. LogManager.GetLogger(someStringOrTypeName);

    • An ILog interface is returned with Debug, Info, Warn, Error, Fatal methods on it for
      tracing. 
  • Logging level is generally inherited from the hierarchy, and be configured anywhere
    in the hierarchy. 

    • Rule: logging level is equal to first non-null value working UP the tree.

    • Predefined levels: DEBUG, INFO, WARN, ERROR, FATAL, ALL, OFF

    • Default level for root in hierarchy is DEBUG 

Appenders: An output destination for logging. 

  • Built in: event log, asp.net trace, console, file, rolling file, smtp, etc.

  • Appenders can optionally have “layouts” to specialize how formatting is done and add
    additional information (windows identity, source code info, context, thread id, timestamp,
    etc.) 

  • Appenders are attached to a logger.  Log requests will go to a given logger’s
    appender, as well as all appenders attached up the hierarchy (unless “additivity=false”
    at some level, in which case moving up hierarchy stops…) 

Filters: A given appender can apply a filter such that only log requests that
match some criteria will actually be output.  Filters are applied sequentially. 
Built-in filters include string match and regex match. 

Configurators: Classes which initialize the log4net environment.  Configuration
is done either through assembly attributes that specify a config file, or an explicit
call to specify a config file.  The config file can be a standard .net config
file, or standalone.  Configuration is by default at the appdomain level, but
can be finer-grained through the use of log4net “logging domains”.

Using log4net with BizTalk 2004

There are a few challenges to using log4net in a BizTalk 2004 environment.  They
can be summarized as follows: 

  • Assembly-attribute-driven configuration won’t work because BizTalk 2004 does
    not appear to support the addition of custom attributes for BizTalk assemblies. 
    (And even if it did, this method would pose issues for BizTalk environments.)  

  • Using the log4net configuration classes for configuration is problematic because there
    is no clear point at which to make the call.  (How does as an orchestration know
    if it is “first” and should initialize?  How does it know at any point
    in an orchestration whether the BizTalk service has been recently recycled, losing
    the log4net configuration?)  Moreover, there is not a good way to identify where
    the configuration file should be located.

  • ILog-derived classes (log4net loggers) are not serializable “out-of-the-box”,
    making it difficult to use them in an orchestration setting.

  • Log4net context-storage mechanisms are thread-relative, which isn’t workable
    for orchestrations, since orchestrations often a) dehydrate and then re-hydrate on
    a different thread and b) make use of parallel branches.  We’d like to
    correctly associate context such as the orchestration instance ID on a logger that
    is scoped to an orchestration. 

To address these challenges, I’ve created extensions
to log4net
that attempt to stay within log4net’s design intent.  These
are housed in an assembly called “log4net.Ext.Serializable”.  (Update
– these are now currently found in the “Extra Tools” download for
the Deployment Framework – see the download links at the blog
home page
.)

The main classes defined are as follows: 

SLog: A serializable implementation of the ILog interface, to be used by orchestrations
(or other components) for logging.  This class has an InstanceId property as
well as a general properties collection that is carried with the logger itself. 
(These can be made available in appender output via a PatternLayout class and the
%P{yourpropname} format specifier.  Use %P{InstanceId} for the InstanceId.) 
When deserialized, this class can detect an un-initialized state for log4net and recreate
the correct configuration. 

SLogManager: To be used in place of log4net’s LogManager to dispense
SLog classes.  This is the accepted way of dispensing custom loggers in log4net’s
design. 

RegistryConfigurator: A class which consults a registry key for the location
of a log4net config file, and creates the configuration in the specified “logging
domain” using the log4net DomConfigurator class. 

Specifics for BizTalk 2004 Usage 

Using the assembly just discussed, the specifics of using log4net with a particular
BizTalk project can be described as follows: 

  • Get 1.2.0 Beta8 of log4net at http://sourceforge.net/project/showfiles.php?group
    id=31983&release id=171808
    .

  • Get the log4net extension described
    above, as well as a full
    sample project
    if you like.  (Update – the
    current version of this sample will now always be found in the Deployment Framework
    sample – see download links at the blog
    home page
    .)

  • If you are using NAnt to deploy your BizTalk solution, extend your customDeployTarget
    as shown below to create a registry key that will point to a log4net configuration
    file within your project’s root directory (whether on a developer desktop or
    an MSI base directory). (Handled for you in current rev
    of deployment framework.)
     Also, create a file with the log4net extension
    that corresponds to your solution name (i.e. BizTalkSample.log4net)

    <target name="customDeployTarget"> 
       <!-- Write registry key with location of our log4net configuration
    file.  This step is NOT needed in current rev of Deployment Framework… -->
       <exec program="cscript.exe" failonerror="true" commandline="/nologo
    ${deployTools}\WriteRegValue.vbs HKLM\SOFTWARE\${nant.project.name}\log4netConfig
    ${nant.project.basedir}\${nant.project.name}.log4net" />
    </target>
  • Orchestration assemblies should reference log4net.Ext.Serializable as well as log4net.dll,
    and declare a variable in each orchestration (perhaps named “logger”)
    of type log4net.Ext.Serializable.SLog.

  • Orchestrations should begin (after an activating receive, if necessary) with an expression
    shape that looks like:

    logger = log4net.Ext.Serializable.SLogManager.GetLogger(@"BizTalkSample",log4net.helpers.CallersTypeName.Name);
    logger.RegistryConfigurator();
    logger.InstanceId = MyOrchName(Microsoft.XLANGs.BaseTypes.InstanceId);
    logger.Debug("New request arrived...");

    Important: If an orchestration has parallel branches, you will want to declare multiple
    variables of type log4net.Ext.Serializable.SLog, assigning 2-n to the first one, as
    in:

    logger2 = logger;

    This prevents the need for synchronizing scopes.  (See this
    article
    for more.)&nbps;An alternative is to use scope-local logger variables
    that are initialized by assigning them to a global instance.

  • At various points in your orchestration, simply make calls to logger.Debug/logger.Info/logger.Error,
    etc.  Rely on logger.Error for event log entries (with appropriate logger/appender
    configuration.)

  • Use log4net with the components that your orchestration calls as well.  If those
    components are serializable, they will want to make use of SLogManager/SLog classes
    as well in non-static methods.  If you want context (such as the orchestration
    instance ID) to flow, it might be worthwhile to make an SLog-typed property visible
    on the class that the orchestration can set.  (This needs more thought.)

Using log4net with Paul Bunyan 

Paul Bunyan is a logging tool that has
a very nice server-side buffering service as well as a great trace-viewing client
that can connect to multiple servers simultaneously (a great plus for BizTalk groups!) 
Although Paul Bunyan has its own API, we aren’t interested in it for purposes
of this discussion.

A log4net appender can be easily written for Paul Bunyan, such that log output can
be directed there.  Moreover, this appender can be made to explicitly recognize
an InstanceId property carried with a log4net logging event, and map it to the “Context”
concept within Paul Bunyan!  This allows for viewing the orchestration instance
ID within a distinct, filterable column in the Paul Bunyan viewer as such:

Paul Bunyan View

(click)

Sample .log4net configuration File 

Note that types have to be referred to with fully-qualified names since log4net.dll
is being deployed to and loaded from the GAC.

<?xml version="1.0" encoding="utf-8" ?>
<log4net>

   <!-- Define some output appenders -->
   <appender name="OutputDebugString" type="log4net.Appender.OutputDebugStringAppender,
        log4net,Version=1.2.0.30714,Culture=Neutral,PublicKeyToken=b32731d11ce58905">
      <layout type="log4net.Layout.PatternLayout,log4net,
           Version=1.2.0.30714,Culture=Neutral,PublicKeyToken=b32731d11ce58905">
         <param name="ConversionPattern" value="%d [%t] %-5p %c - %m [%P{InstanceId}]%n" />
      </layout>
   </appender>

   <appender name="EventLog" type="log4net.Appender.EventLogAppender, log4net, 
        Version=1.2.0.30714, Culture=Neutral, PublicKeyToken=b32731d11ce58905">
      <param name="ApplicationName" value="BizTalkSample" />
      <layout type="log4net.Layout.PatternLayout,log4net,
           Version=1.2.0.30714,Culture=Neutral,PublicKeyToken=b32731d11ce58905">
         <param name="ConversionPattern" value="[%t] %-5p %c - %m [%P{InstanceId}]%n" />
      </layout>
      <!-- Only send error/fatal messages to the event log. -->
      <filter type="log4net.Filter.LevelRangeFilter">
         <param name="LevelMin" value="ERROR" />
         <param name="LevelMax" value="FATAL" />
      </filter>
   </appender>

   <!-- Setup the root category, add the appenders and set the default level -->
   <root>
      <!-- Possible levels (in order of increasing detail):
                     OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL -->
      <level value="ERROR" />
      <appender-ref ref="EventLog" />
   </root>

   <logger name="BizTalkSample">
      <level value="ALL" />
      <appender-ref ref="OutputDebugString" />
   </logger>
   
</log4net>

Wow, how not to design a website…

Wow, how not to design a website…

Owen Cutajar blogged about “The 5 biggest mistakes almost all web designers make“.


I’d like to add a site to the list… I recently tried to browse this page on the  Sony Connect Website from a Windows 2003 PC, only to be informed that:


We appreciate your interest in the Connect music store, but our store currently only works with computers running Windows 98 Second Edition or higher. […] We’ll have to part ways until we support the operating system you’re currently using, or you make the switch to an OS that is compatible with the Connect music store.


Unbelievable. So they think it’s ok to require customers to change OS just to browse their site? I guess that’s one potential customer they’ve lost. Oh well, if I ever downgrade back to Windows 98 I may go back!


(As an aside – if anyone has an alternative source for the MSNBC Tsunami Aid concert, that would be great, since MSNBC Europe showed a programme about stocks and shares instead of the advertised show!)


 

Extending the Custom BizTalk Socket Adapter Sample to support Dynamic Port Binding

Extending the Custom BizTalk Socket Adapter Sample to support Dynamic Port Binding

<b:schemaInfo http: BizTalk schema_type="property" xmlns:b="<b:fieldInfo http: BizTalk xmlns:b="<b:fieldInfo http: BizTalk xmlns:b="

I’ve recently had to go through the process of having to find out how to achieve this so
hopefully I can save other people a lot of time when it comes to creating their custom adapters.


The Socket Adapter sample provided with the Biztalk Adapter Wizard does not support Dynamic Port Binding out of the box, so as an illustrative exercise I have prepared a walkthrough to show how to make it work with Dynamic Ports.


You have two options:


OPTION 1  – Work through the code yourself (Recommended)


Familiarise yourself with the Pre-requisites.


1) Read Christof Claessens excellent article that touches on dynamic send port binding. It’s located at
http://weblogs.asp.net/christof_claessens/archive/2004/06/18.aspx
There is a section that explains how you can use Dynamic Port Binding with the out of the box FTP adapter
2) Work through creating the sample Socket Adapter using the
“Developing a BizTalk Server 2004 Socket Adapter with the Adapter Wizard.doc” that’s located in the “BTSAW11.zip”, available for download from
http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=c95217fc-4f9f-4fec-9d68-1aa9456b6ca0
Make sure that you can get it working before continuing.


Make adapter “message context properties” visible to an Orchestration


1) Add a new BizTalk project to the BizTalk Socket Adapter Solution called “SocketPropertySchema”
2) Add a the following Property Schema as “PropertySchema.xsd” to your SocketPropertySchema project


<?xml version=”1.0″ encoding=”utf-16″?>
<xs:schema xmlns=”
http://schemas.unisys.com/BizTalk/Adapters/SocketAdapter” xmlns:b=”http://schemas.microsoft.com/BizTalk/2003” targetNamespace=”http://schemas.unisys.com/BizTalk/Adapters/SocketAdapter” xmlns:xs=”http://www.w3.org/2001/XMLSchema“>
  <xs:annotation>
    <xs:appinfo>
      <b:schemaInfo schema_type=”property” xmlns:b=”
http://schemas.microsoft.com/BizTalk/2003” />
    </xs:appinfo>
  </xs:annotation>
  <xs:element name=”RemoteHostName” type=”xs:string”>
    <xs:annotation>
      <xs:appinfo>
        <b:fieldInfo propSchFieldBase=”MessageContextPropertyBase” xmlns:b=”
http://schemas.microsoft.com/BizTalk/2003” propertyGuid=”1a0116b8-e2c7-4da2-9f43-414686d38005″ />
      </xs:appinfo>
    </xs:annotation>
  </xs:element>
  <xs:element name=”RemotePortNr” type=”xs:int”>
    <xs:annotation>
      <xs:appinfo>
        <b:fieldInfo propSchFieldBase=”MessageContextPropertyBase” xmlns:b=”
http://schemas.microsoft.com/BizTalk/2003” propertyGuid=”7a8a8133-4aff-4af4-8ae9-62f8ef056d87″ />
      </xs:appinfo>
    </xs:annotation>
  </xs:element>
</xs:schema>


NOTE –  the propSchFieldBase=”MessageContextPropertyBase” xmlns:b=”http://schemas.microsoft.com/BizTalk/2003” attributes have to be manually added if you need to add new elements.
The schema editor does not add them.


NOTE – the xmlns and targetNamespace attributes were set to the same value as the PropertyNamespace value that was found in the SocketAdapter.reg that is provided in the sample adapter solution directory.


3) If it wasn’t already set make sure you set the build action of PropertySchema.xsd to “compile”.


4) Assign a strong name to the project “SocketAdapterTester.snk” otherwise you wont be able deploy it to BizTalk.


5) Build and Deploy the SocketPropertySchema project


6) Reference the SocketPropertySchema  from the SocketAdapterTester project


Once you have completed this task the message context properties will be available for setting in an orchestration message construct shape , just like in Christoph’s example for the FTP adapter.


You’ll be able to set them in a similar manner to the examples below (the actual property names my differ slightly but will start with “Socket”)


msgServerOrder(SocketAdapterPropertySchema.PropertySchema.RemoteHostName) = “biztalktest”;
msgServerOrder(SocketAdapterPropertySchema.PropertySchema.RemotePortNr) = 8999;


Modify the Sample Socket Adapter Code to enable it to access the new message context properties


Unfortunately the adapter code in its current format doesn’t automatically “know” that these are the values to use.
In fact there is no real relationship between the elements set up in the Transmit Location.xsd and the PropertySchema.xsd files.


So we have to modify the socket adapter code to deal with this new data.


The following is merely an illustration i.e. it reflects the key points in order to make the adapter support Dynamic Port Binding.
I have probably skipped over a number of vital error handling routines so ensure that you add the necessary error trapping routines in your
production code.



1. Modify the following code snippet located in the SocketTransmitAdapterBatch.cs .


Old Code


remote_host.PortNr = config.RemotePortNr;
remote_host.TimeOut = SocketAdapterProperties.Timeout*1000;


New Code


if (null != config)
{
    //It’s a static port
    remote_host.ServerName = config.RemoteHostName;                                     
    remote_host.PortNr = config.RemotePortNr;
}
else
{
    //It’s a dynamic port. No properties are available if it’s Dynamic so we have to get them from Message Context
    remote_host.ServerName = msg.Message.Context.Read (“RemoteHostName”,”
http://schemas.unisys.com/BizTalk/Adapters/SocketAdapter”).ToString();
    remote_host.PortNr = Convert.ToInt32(msg.Message.Context.Read(“RemotePortNr”,”
http://schemas.unisys.com/BizTalk/Adapters/SocketAdapter“));
}


Stop the Biztalk Server and any send ports. Rebuild the Solution (sometimes WMI has a hold on the assemblies . Use sysinternals handle.exe to determine this)
Now all that is left is for you to test your adapter by modifying the existing sample orchestration.


Modifying The “SocketAdapterTester” Project to use Dynamic Port Binding


Now that we have added Dynamic support to our adapter we can modify an existing orchestration to use a Dynamic Solicit Response Send Port.


1. Undeploy the existing “SocketAdapterTester”  assembly from your Biztalk server.
2. Open up the OrchSocketClient.odx , delete the “psrSolRspSocketClient” port from the orchestration
3. Add a new Configured Port with the following values


Name:    portSendDynamic
portType :   portTypeDynamic
Pattern :    Request Response
Direction:  Send Receive
Port Binding :  Dynamic
Receive Pipeline: XmlReceive
Send Pipeline:  XmlReceive


4. In Orchestration Properties add a new message called “msgServerOrder2” of same type as “msgServerOrder”


5. Add a Construct Message Shape immediately under the rcvFromFile Receive Shape. Name it “Create msgServerOrder2” . Set the Messages Constructed property to msgServerOrder2
6. Drag a Message Assignment Shape into the Construct Message shape.Name it “from msgServerOrder”
set the expression to :


msgServerOrder2 = msgServerOrder;



7. Drag another Message Assignment Shape into the Construct Message shape.Name it “Set Context”
set the expression to : (replace biztalktest with your machine name. )



msgServerOrder2(SocketAdapterPropertySchema.PropertySchema.RemoteHostName)=”biztalktest”;
msgServerOrder2(SocketAdapterPropertySchema.PropertySchema.RemotePortNr)=8999;


NOTE – Exact Message context properties name may differ slightly from what’s outline above , depending on the namespace assigned to the PropertySchema.xsd file.
You should be able to locate the values as they will more than likely start with “Socket”.
8. Drag an Expression shape immediately below the Construct Message Shape and before the sndToSocket shape , name it “Set Dynamic Port”
Set the expression to : (change biztalktest to your machine name)



portSendDynamic(Microsoft.XLANGs.BaseTypes.Address)=”Socket://biztalktest/8999″;


9. Modify the sndToSocket Shape and set its Message property to msgServerOrder2 instead of msgServerOrder.
10. Re-connect the sndToSocket and rcvFromSocket shapes to the portSendDynamic port.
11. Stop the Biztalk Server Host and any send ports that may be using the adapter.
You may need to close down Server Administration and Biztalk Explorer as sometimes they seem to keep hold of the assemblies.(use handle to find any locked assemblies)
12. Rebuild the solution. If there are any build issues then revisit the previous steps.
13. Re-Start the BizTalk host
14. Deploy the modified “SocketAdapterTester” Project.
15. As part of the standard Socket Adapter walkthrough you will have created two file locations called rcvFromFile and sndToFile
Make sure they have provided the necessary read / write permissions to allow Biztalk to access them.
17. Bind and Start the “SocketAdapterTester.OrchSocketClient” and “SocketAdapterTester.OrchSocketServer” Orchestrations
NOTE – The orchestration “SocketAdapterTester.OrchSocketClient” should have already pre-bound its send port to the auto-generated dynamic port)
NOTE – With the exception of the new Dynamic port , bind all other ports as per the Socket Adapter Walkthrough.
18. Start the socket listener client as per the socket adapter walkthrough
19. Drop the following Xml sample instance into the “rcvFromFile” file receive location.


<ns0:ServerPO xmlns:ns0=”http://SocketAdapterTester.POSchema“>
  <Manufacturer>Unisys</Manufacturer>
  <Type>ES 7000 Orion 560</Type>
  <NrOfProcessors>32</NrOfProcessors>
  <AmountOfRam>64 GB</AmountOfRam>
  <Quantity>12</Quantity>
</ns0:ServerPO>



20. The xml file should be processed just like it was in with the Static Send Port.


OPTION 2 – Use my sample code (based upon the original socket adapter sample code.)


NOTE – this sample is hard coded to work from a specific directory location on the C drive.
For convenience , I have added assembly-binding files, send and receive locations and also have strong named the assemblies.
But the following step-by-step instructions apply ONLY to the default solution location.
You’ll need to modify the assembly binding file and the adapter registry file if you decide to use a different file location.


1. If you have previously used the SocketSample adapter code provided with the BizTalk Adapter Wizard , you MUST ensure that you have removed
the adapter and any old send and receive ports prior to using this sample code. Otherwise you will have problems re-registering and re-adding the adapter.
1. Download the source code from
http://www.appsolutions.co.uk/samples/SocketSample.zip
2. Extract the zip file to your C drive. It will create a “SocketSample” folder on the C drive.
3. Open the “C:\SocketSample\BizTalk Server Socket Adapter Sample\BizTalk Socket Adapter.sln” solution.
4. In the SocketRecvListener project modify the SocketRecvListener.cs to replace the machine name “biztalktest” with your machine name.
NOTE – You can optionally change the port and uri values but I would recommend leaving them as they are, otherwise you will have to change your assembly binding files to make the sample work properly.
5. Build the entire solution.
6. Run the C:\SocketSample\BizTalk Server Socket Adapter Sample\SocketAdapter.reg to import the necessary adapter registry details
7. Add the adapter using Biztalk Server Administration>>Adapters>>New>>Adapter. Once done you must stop the Biztalk host.
8. Set the Send Handler Properties on the adapter. Set MaxBufferSize to 49152 and Timeout to 20.
9. Deploy the SocketAdapterPropertySchema and SocketAdapterTester Biztalk projects (in that order).
10.Modify the C:\SocketSample\AssemblyBinding\SocketBinding.xml. Replace any occurrences of “biztalktest” with your machine name.
10. Once that is done you can import this assembly-binding file (SocketBinding.xml) using the Biztalk Server Deployment Wizard
11. Assign read/write permissions to the C:\SocketSample\rcvFromFile and C:\SocketSample\sndToFile directories
12. Start the “SocketAdapterTester.OrchSocketClient” and “SocketAdapterTester.OrchSocketServer” Orchestrations, including send and receive ports etc.
13. Start the Socket Listener Client , located in “C:\SocketSample\BizTalk Server Socket Adapter Sample\SocketRecvListener\bin\Debug\SocketRecvListener.exe”
14. Start the Biztalk Host (if not already started).
15. Drop the “C:\SocketSample\SampleInstance\SampleInstance.xml” file into “C:\SocketSample\rcvFromFile”
16. Biztalk will process the file (via the socket listener) and place an output file in the “C:\SocketSample\sndToFile” directory
17. Take the time to review the OPTION 1 to familiarise yourself with what has been modified. If you have time work through Option 1 to get yourself familiar with the principles
because once you’ve done it once the method should be the same some any new adapters you create.


Conclusion


I hope this post was of use. If you have any problems with this walkthrough let me know and time permitting I’ll do my very best to assist you. Code is provided as is. No guarantees are made as it its ability to perform in a production environment.


 


 

BizTalk Server 2004: Direct Binding Models in BizTalk – corrected!

BizTalk Server 2004: Direct Binding Models in BizTalk – corrected!

My thanks to Gregory Van de Wiele who raised some questions over my statements about call-back patterns in my recent article on Direct Binding.   In attempting to dispel some myths, I was indeed adding my own!!   I had failed to understand the implications of the differences between Call Orchestration and Send Orchestration shapes, and the additional ways in which self-correlating ports can be used specifically with Start Orchestration shapes.   I have issued an amended and corrected version of the article.

Using the User Interface Process Application Block 2 in conjunction with the Configuration Management Application Block

Using the User Interface Process Application Block 2 in conjunction with the Configuration Management Application Block

In my existing project I wanted to be able to store my User Interface Process configuration data OUTSIDE of my standard application configuration file (i.e. appname.exe.config or web.config). I felt that I was going to have a significant amount of navigational and process configuration data and I personally would be far happier storing it away from the standard config file. 


Perhaps I gave up too soon with the documentation and I am sure there is probably a sweeter way of achieving this requirement, but anyway here goes. Feel free to correct me if there is a better solution.


If want to store your User Interface Process Application Block 2 (UIPAB2) configuration data outside of the your main application configuration file then one method of achieving this is could be by using the Configuration Management Application Block (CMAB) in conjunction with the UIPAB2.



Conditions Of Using This Method

a) This method assumes you have working knowledge of both the UIPAB2 and the CMAB
b) You have to make very minor changes to the UIPAB2 source code in order to utilize this functionality . To download the the source code go to http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/uipab.asp

The process of creating a UIPAB2 application is no different to normal. For tips on how to create applications using the UIPAB take a look at http://www.codeproject.com/dotnet/UIPAB1.asp and http://www.codeproject.com/dotnet/UIPAB2.asp for some great demos.

Incorporating the CMAB into your UIPAB2 project

STEP 1 – Add the Configuration Management Application Block and UIPAB2 to your solution. From the UIPAB2 project add a reference to it from the CMAB

STEP 2 – Add / amend you application configuration file to include the standard CMAB sections as shown in the sample below:

<configuration>
<!–The configSections and applicationConfigurationManagement sections are required for the CMAB–>
<configSections>
<section name=”applicationConfigurationManagement” type=”Microsoft.ApplicationBlocks.ConfigurationManagement.ConfigurationManagerSectionHandler,Microsoft.ApplicationBlocks.ConfigurationManagement, Version=1.0.0.0,Culture=neutral,PublicKeyToken=null” />
<section name=”uipConfiguration” type=”Microsoft.ApplicationBlocks.UIProcess.UIPConfigHandler, Microsoft.ApplicationBlocks.UIProcess, Version=1.0.1.0,Culture=neutral,PublicKeyToken=null”/>
</configSections>
<applicationConfigurationManagement>
<!–Implementation of the UIPAB as part of configuration management as opposed to using the standard config file readers–>
<!–Note that in this section we are pointing to an external configuration file, however we could be using any of the inbuilt CMAB functionality to hold the UIPAB configuration–>
<configSection name=”uipConfiguration”>
<configProvider assembly=”Microsoft.ApplicationBlocks.ConfigurationManagement,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null” type=”Microsoft.ApplicationBlocks.ConfigurationManagement.Storage.XmlFileStorage” signed=”false” refreshOnChange=”true” encrypted=”false” path=”..\..\..\TestConfigFile.config” />
</configSection>
</applicationConfigurationManagement>
<!–Usually the UIPAB config sections would appear here in the Config file. –>
<!–Because we are delegating the task to the CMAB they have been moved out–>
<!–to a seperate file location called TestConfigFile.config–>
</configuration>

STEP 3 – Move / create your UIPAB2 configuration file as per the sample shown below. NOTE THE USE OF TWO uipConfiguration nodes. This is due to differences in the way that the standard configuration reader works compared to the CMAB readers.

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
<uipConfiguration>
<uipConfiguration>
<objectTypes>
<iViewManager
name=”ViewManager”
type=”Microsoft.ApplicationBlocks.UIProcess.WindowsFormViewManager, Microsoft.ApplicationBlocks.UIProcess, Version=1.0.1.0,Culture=neutral,PublicKeyToken=null”/>
<state
name=”State”
type=”Microsoft.ApplicationBlocks.UIProcess.State, Microsoft.ApplicationBlocks.UIProcess, Version=1.0.1.0,Culture=neutral,PublicKeyToken=null”/>
<controller
name=”UIController”
type=”InterfaceProcess.UIController, InterfaceProcess, Version=1.0.0.0,Culture=neutral,PublicKeyToken=null” />
<statePersistenceProvider
name=”MemoryStatePersistence”
type=”Microsoft.ApplicationBlocks.UIProcess.MemoryStatePersistence, Microsoft.ApplicationBlocks.UIProcess, Version=1.0.1.0,Culture=neutral,PublicKeyToken=null”/>
</objectTypes>
<views>
<view
name=”Explanation”
type=”DemoWindowsFormsApplication.Explanation, DemoWindowsFormsApplication, Version=1.0.1.0,Culture=neutral,PublicKeyToken=null”
controller=”UIController”/>
<view
name=”Thanks”
type=”DemoWindowsFormsApplication.Thanks, DemoWindowsFormsApplication, Version=1.0.1.0,Culture=neutral,PublicKeyToken=null”
controller=”UIController”/>
</views>
<navigationGraph name=”Nav”
startView=”Explanation”
state=”State”
statePersist=”MemoryStatePersistence”
iViewManager=”ViewManager”>
<node view=”Explanation”>
<navigateTo navigateValue=”Thanks” view=”Thanks” />
</node>
</navigationGraph>
</uipConfiguration>
</uipConfiguration>
</configuration>

STEP 4 – In the UIPAB2 Project open the Configuration\UIPConfiguration.cs file and add the following using directive :

using Microsoft.ApplicationBlocks.ConfigurationManagement;

STEP 5 – Modify the following line of code: (located in the public static UIPConfigSettings Config declaration)

Old Code

_currentConfig = (UIPConfigSettings)ConfigurationSettings.GetConfig( UipConfigSection );

New Code

_currentConfig = (UIPConfigSettings) ConfigurationManagement.ConfigurationManager.Read(UipConfigSection);

Sample Code Available For Download

Sample code is available for downloand from http://www.appsolutions.co.uk/samples/CombiningUIPABwithCMAB.zip

Post is provided as is. No guarantees are made as to its ability to function in a production environment.