dinsdag 22 mei 2012

joined BizTalkAdminsBlogging.com

My personal blog only exists for a year and a half now, but already has quite some visitors. Yesterday I was even asked to join another Biztalk blogging team on Biztalk administrator related topics. I already knew the blog and was a frequent visitor of the website. Of course I was glad to join the Biztalk blog team.

So, as of  today I joined several other biztalk experts on the BizTalk admin blog BizTalkAdminsBlogging.com.
This blog is dedicated to provide BizTalk admins with useful information, tips, example scripts and everything else that is interesting for a BizTalk admin.

I will still publish posts to this blog, but I will also write an occasional blog post for the BizTalkAdminsBlogging.com website... My first post on the site still has to be written, and any suggestions are always welcome :).

My profile on BizTalkAdminsblogging.com: http://www.biztalkadminsblogging.com/index.php/component/k2/itemlist/user/59-mitchvanhelden

maandag 21 mei 2012

Guideline to Solve Performance issues of Biztalk

Typically a performance problem can be narrowed down to one of the following components of a BizTalk Server environment:
·         A receive adapter or the system from which the adapter is receiving documents. For example, if documents are being received by the HTTP adapter at a suboptimal rate then the problem may be with the HTTP receive adapter or with the client that is posting to the HTTP adapter.
·         An orchestration service instance.
·         Performance of the SQL Server that hosts the BizTalk Server databases.
·         A send adapter or the system that the adapter is sending documents to. For example, if documents are being sent by the SQL adapter at a suboptimal rate then the problem may be with the SQL send adapter or with the computer running SQL Server that the SQL adapter is updating.

Use the following guidelines to help identify the components of the BizTalk Server environment that are performing poorly:
·         Capture any warnings or errors generated in the BizTalk Server or SQL Server Event Viewer.
·         Follow the steps in "Identifying Performance Bottlenecks" in BizTalk Server Help at http://go.microsoft.com/fwlink/?LinkId=154238 to help identify performance bottlenecks.
Once the poorly performing component has been identified, follow the appropriate guidelines to help resolve the issue:
Guidelines for resolving performance problems related to send and receive adapters
·         For information about troubleshooting problems with BizTalk Server adapters, see "Troubleshooting BizTalk Server Adapters" in BizTalk Server Help at http://go.microsoft.com/fwlink/?LinkId=154240. This section contains general troubleshooting information including information about how to set up logging for certain adapters, and information that can be used diagnose network problems, problems with MSDTC, problems with the registry, problems with the file system, and problems with IIS.
·         For information about troubleshooting problems with MSDTC, certificates, Enterprise Single Sign-On, and SQL Server, see the appropriate section of "Troubleshooting BizTalk Server Dependencies" in BizTalk Server Help at http://go.microsoft.com/fwlink/?LinkId=154242.
Guidelines for resolving performance problems related to orchestrations
·         For information about modifying the appropriate sections of the BTSNTSvc.exe.config file, see "Orchestration Engine Configuration" in BizTalk Server Help at http://go.microsoft.com/fwlink/?LinkId=154244.
Guidelines for resolving performance problems related to SQL Server
·         SQL Server Profiler can be used to capture Transact-SQL statements that are sent to SQL Server and the SQL Server result sets from these statements. Since BizTalk Server is tightly integrated with SQL Server, the analysis of a SQL Server Profile trace can be a useful tool for analyzing problems that may occur in BizTalk Server when reading from and writing to SQL Server databases. For information about how to use SQL Server Profiler, see "Using SQL Server Profiler" in SQL Server Books Online at http://go.microsoft.com/fwlink/?linkid=104423.
·         SQL Server Management Studio can be used to execute SQL statements directly against SQL Server databases. This functionality may be useful for querying the BizTalk Server databases or for updating the BizTalk Server databases in certain scenarios. For more information about using SQL Server Management Studio to execute SQL statements, see "Writing, Analyzing, and Editing Scripts with SQL Server Management Studio" in SQL Server Books Online at http://go.microsoft.com/fwlink/?linkid=104425.
·         For more information about resolving performance problem related to the BizTalk Server databases, see "Troubleshooting SQL Server" in BizTalk Server Help at http://go.microsoft.com/fwlink/?LinkId=154250.

woensdag 9 mei 2012

SAP calling RFC hosted in BizTalk

 I've configured a SAP receive port in BizTalk. However when trying to enable the receive location I got some errors in the error log saying ' 'saprfc.ini' failed: 'No such file or directory' '.  Here is the full error message:

The Messaging Engine failed to add a receive location "RECEIVE MIXED ERIKS SAP" with URL "sap://CLIENT=900;LANG=EN;@a/SAPSERVER/00?GWSERV=sapgw00&ListenerDest=TRADCOMSAPDEST&ListenerGwServ=sapgw00&ListenerGwHost=194.178.122.5&ListenerProgramId=TRADCOMSAPPROG&RfcSdkTrace=False&AbapDebug=False" to the adapter "WCF-SAP". Reason: "Microsoft.Adapters.SAP.RFCException: Details: ErrorCode=RFC_OK. ErrorGroup=RFC_ERROR_SYSTEM_FAILURE. SapErrorMessage=Open file 'saprfc.ini' failed: 'No such file or directory'.  AdapterErrorMessage=Error accepting incoming connection. RfcAccept returned RFC_HANDLE_NULL..

Apparently this file is used in the RFC library of SAP:
“The RFC library will read the saprfc.ini file to find out the connection type and all RFC-specific parameters needed to connect to an SAP system, or to register an RFC server program at an SAP gateway and wait for RFC calls from any SAP system.”

How to solve this issue?

First of all you'll need to create a System Variable called RFC_INI. To manage the Environment Variables you'll need to open the system properties and select 'Environment Variables...', as shown below.


Then create the new system variable RFC_INI with a filepath as value, for example C:\SAPINI\saprfc.ini.
 

Next we need to add the contents to our saprfc.ini file.  The values that I needed to provide include: 

FieldValuedescription
DEST TRADCOMSAPDEST In this case, this is the name of the RFC Destination that our BASIS team created for us from SM59.  More details here.
TYPE R Type R is for RFC server programs or for a client program working with another external program as RFC server program which is already registered at an SAP gateway.
GWHOST SAP_HOST_NAME In my case, this is the name of the physical server that his hosting the SAP Gateway.
GWSERVER SAP_GATEWAY_NAME The name of the SAP Gateway.  A standard naming convention is: SAPGW## where ## is the system number for the SAP instance that you are working on.
PROGID TRADCOMSAPPROG This is the name of the Program ID that has also been provided by BASIS. 



When you compare the data between the Receive Location and the saprfc.ini file, you'll see a certain symmetry between the two.  However, the values in the ini file take precedence.<br />

 
You'll need a restart of the BizTalk host instance, the one defined on the SAP adapter, for the changes to take effect.
This should be all to resolve the issue.

Source: Kent Weare's BizTalk Blog: SAP calling RFC hosted in BizTalk

woensdag 25 april 2012

Calling Pipelines with custom property settings from an orchestration

In my previous blog post I explained how to execute pipelines from an orchestration using the default pipeline property settings.
Now I would like to show you how to call pipelines from an orchestration while configuring the pipeline with custom property settings. To achieve this the standard methods wouldn't suffice.

First of all you'll need to add some extra functionalities. Here's my code to achieve this:
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Data.SqlClient;
using System.Runtime.Serialization;

using Microsoft.XLANGs.Pipeline;
using Microsoft.BizTalk.PipelineOM;
using Microsoft.XLANGs.BaseTypes;
using System.IO;
using System.Reflection;
using System.Collections;
using System.Data;
using System.Text.RegularExpressions;
using Microsoft.XLANGs.RuntimeTypes;
using Microsoft.XLANGs.Core;
using MIME;
using System.Net;

namespace TP.BTS.GlobalFunctions
{

public class PipelineInstance
    {
        internal Microsoft.BizTalk.PipelineOM.Pipeline pipeline = null;

        public static PipelineInstance CreateInstance(Type type)
        {
            PipelineInstance instance = new PipelineInstance();
            instance.pipeline = (Pipeline)Activator.CreateInstance(type);
            return instance;
        }

        public void ApplyInstanceConfig(String config)
        {
            try
            {
                using (Stream stream = new MemoryStream(Encoding.Unicode.GetBytes(config)))
                    LoadPerInstanceConfig(pipeline, stream);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(String.Format("{0}", e));
                throw;
            }
        }

        #region Implementation

        private static void LoadPerInstanceConfig(Pipeline pipeline, Stream stream)
        {
            try
            {
                MethodInfo method =
                    typeof(Pipeline).GetMethod(
                        "LoadPerInstanceConfig"
                        , BindingFlags.NonPublic | BindingFlags.Instance);
                method.Invoke(pipeline, new object[] { stream });
            }
            catch (System.Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e);
                throw;
            }
        }

        #endregion
    }

    public static class PipelineManager
    {
        #region receive pipeline
        public static ReceivePipelineOutputMessages ExecuteReceivePipeline(Type type, XLANGMessage message)
        {
            string EmptyConfig =
                        @"<Root
                        xmlns:xsd='http://www.w3.org/2001/XMLSchema'
                        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
                        <Stages />
                    </Root>";

            return ExecuteReceivePipeline(type, EmptyConfig, message);
        }

        public static ReceivePipelineOutputMessages ExecuteReceivePipeline(Type type, String config, XLANGMessage message)
        {
            try
            {
                PipelineInstance pipeline = PipelineInstance.CreateInstance(type);
                pipeline.ApplyInstanceConfig(config);
                return ExecuteReceivePipeline(pipeline, message);
            }
            catch (TargetInvocationException e)
            {
                System.Diagnostics.Debug.WriteLine(e);
                ThrowPipelineException(e);
                throw;
            }
            catch (XLANGPipelineManagerException e)
            {
                throw;
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Assert(false, String.Format("Unexpected exception: {0}", e));
                System.Diagnostics.Debug.WriteLine(e);
                throw;
            }
        }

        public static ReceivePipelineOutputMessages ExecuteReceivePipeline(PipelineInstance pipeline, XLANGMessage message)
        {
            Microsoft.BizTalk.PipelineOM.Pipeline pipelineOM = pipeline.pipeline;

            try
            {
                MethodInfo method =
                    typeof(XLANGPipelineManager).GetMethod(
                        "ExecutePipeline"
                        , BindingFlags.NonPublic | BindingFlags.Static
                        , null, new Type[] { typeof(ReceivePipeline), typeof(XLANGMessage) }
                        , null);
                return (ReceivePipelineOutputMessages)method.Invoke(null, new object[] { pipelineOM, message });
            }
            catch (TargetInvocationException e)
            {
                System.Diagnostics.Debug.WriteLine(e);
                ThrowPipelineException(e);
                throw;
            }
        }
        #endregion

        #region send pipeline
        public static void ExecuteSendPipeline(Type type, SendPipelineInputMessages pipelineinputmsg, XLANGMessage message)
        {
            string EmptyConfig =
                        @"<Root
                        xmlns:xsd='http://www.w3.org/2001/XMLSchema'
                        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
                        <Stages />
                    </Root>";

            ExecuteSendPipeline(type, EmptyConfig, pipelineinputmsg, message);
        }

        public static void ExecuteSendPipeline(Type type, String config, SendPipelineInputMessages pipelineinputmsg, XLANGMessage message)
        {
            try
            {
                PipelineInstance pipeline = PipelineInstance.CreateInstance(type);
                pipeline.ApplyInstanceConfig(config);
                ExecuteSendPipeline(pipeline, pipelineinputmsg, message);
            }
            catch (TargetInvocationException e)
            {
                System.Diagnostics.Debug.WriteLine(e);
                ThrowPipelineException(e);
                throw;
            }
            catch (XLANGPipelineManagerException e)
            {
                throw;
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Assert(false, String.Format("Unexpected exception: {0}", e));
                System.Diagnostics.Debug.WriteLine(e);
                throw;
            }
        }

        public static void ExecuteSendPipeline(PipelineInstance pipeline, SendPipelineInputMessages pipelineinputmsg, XLANGMessage message)
        {
            Microsoft.BizTalk.PipelineOM.Pipeline pipelineOM = pipeline.pipeline;

            try
            {
                MethodInfo method =
                    typeof(XLANGPipelineManager).GetMethod(
                        "ExecutePipeline"
                        , BindingFlags.NonPublic | BindingFlags.Static
                        , null, new Type[] { typeof(SendPipeline), typeof(SendPipelineInputMessages), typeof(XLANGMessage) }
                        , null);
                method.Invoke(null, new object[] { pipelineOM, pipelineinputmsg, message });
            }
            catch (TargetInvocationException e)
            {
                System.Diagnostics.Debug.WriteLine(e);
                ThrowPipelineException(e);
                throw;
            }
        }
       
        #endregion

        #region Implementation

        private static void ThrowPipelineException(Exception innerException)
        {
            ConstructorInfo constructor =
                typeof(XLANGPipelineManagerException).GetConstructor(
                    BindingFlags.NonPublic | BindingFlags.Instance
                    , null
                    , new Type[] { typeof(String), typeof(Exception) }
                    , null);
            throw (XLANGPipelineManagerException)constructor.Invoke(
                    new object[] {
                    innerException != null ? 
                    innerException.InnerException.Message != null? 
                    innerException.InnerException.Message : innerException.Message: 
                    String.Empty, innerException });
        }

        #endregion
    }
    }

Now, here's how to execute a receive pipeline using the custom property settings.
First create a variable of type TP.BTS.GlobalFunctions.PipelineInstance (called ReceivePipeline in my example). Also create a variable PipelineOutputMsg of type Microsoft.XLANGs.Pipeline.ReceivePipelineOutputMessages.
This would be the code to execute the pipeline then:
ReceivePipeline = 
TP.BTS.GlobalFunctions.PipelineInstance.CreateInstance(typeof(TC_FFRECEIVE.TC_FFRECEIVE));

ReceivePipeline.ApplyInstanceConfig(
@"<Root xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
  <Stages>
    <Stage CategoryId='9d0e4103-4cce-4536-83fa-4a5040674ad6'>
      <Components>
        <Component Name='TP.BTS.PIPELINES.CustomXMLRECEIVECOMPONENT'>
          <Properties />
        </Component>
      </Components>
    </Stage>
    <Stage CategoryId='9d0e4105-4cce-4536-83fa-4a5040674ad6'>
      <Components>
        <Component Name='Microsoft.BizTalk.Component.FFDasmComp'>
          <Properties>
            <DocumentSpecName vt='8'>FLATFILE.ORDERS.FF_ORDERS,FLATFILE.ORDERS, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a8e07cee919011d4</DocumentSpecName>
          </Properties>
        </Component>
      </Components>
    </Stage>
  </Stages>
</Root>");



PipelineOutputMsg = TP.BTS.GlobalFunctions.PipelineManager.ExecuteReceivePipeline(ReceivePipeline,MsgICMTxt);
The XML assigned when calling the ApplyInstanceConfig is the same as you can find when exporting the binding file with the Biztalk Admin Console.
It is that simple :).

Calling a send pipeline with custom property settings would be done like this:
Create a variable SendPipelineInput from type Microsoft.XLANGs.Pipeline.SendPipelineInputMessages. I've also used a variable PipelineConfig of type System.String.
Here's the code I've used:
SendPipelineInput.Add(MsgINVOIC_EDI);

PipelineConfig = @"<Root xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>
  <Stages>
    <Stage CategoryId='9d0e4101-4cce-4536-83fa-4a5040674ad6'>
      <Components>
        <Component Name='TP.BTS.PIPELINES.CUSTOMSENDEDIPARTYRESOLUTION.CUSTOMSENDEDIPARTYRESOLUTION'>
          <Properties>
            <OverrideRcvprn vt='8'>" + MsgINVOIC_GEN(ORDERS.ORDERSPropertySchema.RCVPRN) + @"</OverrideRcvprn>
            <OverrideRecipient vt='11'>-1</OverrideRecipient>
            <OverrideSndprn vt='8'>" + MsgINVOIC_GEN(ORDERS.ORDERSPropertySchema.SNDPRN) + @"</OverrideSndprn>
          </Properties>
        </Component>
      </Components>
    </Stage>
    <Stage CategoryId='9d0e4107-4cce-4536-83fa-4a5040674ad6'>
      <Components>
        <Component Name='Microsoft.BizTalk.Edi.Pipelines.EdiAssembler'>
          <Properties />
        </Component>
      </Components>
    </Stage>
    <Stage CategoryId='9d0e4108-4cce-4536-83fa-4a5040674ad6'>
      <Components>
        <Component Name='TP.BTS.PIPELINES.CustomXMLSENDCOMPONENT'>
          <Properties />
        </Component>
      </Components>
    </Stage>
  </Stages>
</Root>";

OrdersOutputInterchange = null;

TP.BTS.GlobalFunctions.PipelineManager.ExecuteSendPipeline(typeof
(CUSTOM_EDI_SEND.CUSTOM_EDI_SEND), PipelineConfig, SendPipelineInput,OrdersOutputInterchange);
And that should do the trick.

Hope you enjoyed this post.

vrijdag 20 april 2012

Call pipelines from an orchestration

Calling a pipeline from an orchestration is quite easy.

First of all you need to add a reference to the Microsoft.XLANGs.Pipeline.dll and Microsoft.BizTalk.Pipeline.dll assemblies. When this is done you'll be able to execute a receive pipeline as follows:
ReceivePipelineOutput = Microsoft.XLANGs.Pipeline.XLANGPipelineManager.ExecuteReceivePipeline
(typeof(ShemasAndPipelines.ReceiveCustOrdres), OrdersInputInterchange);
To get all messages coming out the pipeline, you'll have to loop over the batch and get all messages like this:
 ReceivePipelineOutput.GetCurrent(OrdersInputMsg);
For the execution of a send pipeline you'll need to create a variable of type Microsoft.XLANGs.Pipeline.SendPipelineInputMessages. then call the method add on this variable which adds message of type Microsoft.XLANGs.BaseType.XLANGMessage.
SendPipelineInputMessages.Add(OrderSummary);
To execute the send pipeline, you'll have call the ExecuteSendPipeline method with the just created SendPipelineInputMessages and the output message as follows:
Microsoft.XLANGs.Pipeline.XLANGPipelineManager.ExecuteSendPipeline(typeof
(ShemasAndPipelines.SendCustOrdersPipeline), SendPipelineInput, OrdersOutputInterchange);
This way of executing pipelines will execute the pipelines using the default settings for all pipeline properties. How to execute pipelines from an orchestration with custom settings for the pipeline properties will be explained in my next blogs.

a more detailed explanation can be found here

donderdag 29 maart 2012

Backup BizTalk: Don't make ordinary Full backups

Off course you make backups of your BizTalk databases! You have set the Recovery Model from the databases to Full and every single day your Maintenance Plans or (actually) the SQL Server Agent jobs make Full and Log backups. So in case you need to restore your BizTalk databases, you are safe...
Well, I've got some news for you... You're not so safe...

If you make BizTalk Backups like described above, you could be in deep trouble in case you need to restore. When it comes to making backups from your BizTalk databases, Microsoft supports only one way....

Read this very nice written blog on how to backup Biztalk Databases the right way: Backup BizTalk: Don't make ordinary Full backups