Referencing a port in an orchestration via a string variable - biztalk

I am attempting to develop a generic BizTalk application for configuring dynamic ports. I have an orchestration that pulls back all the configuration settings for each port and I want to loop through these settings and configure the ports. The settings are held in MSSQL and, for instance, two of the properties are PortName and Address. So from within the orchestration I would like to reference the port by the string variable PortName. So is there some way to get a collection of all the ports in an orchestration or reference a port via a string variable i.e. Port['MyPortName'](Microsoft.XLANGs.BaseTypes.Address) = "file://c:\test\out\%MessageId%.xml" Thanks

In order to dynamically configure Dynamic Logical Send Ports from within an orchestration, one has to store the settings into a persistent datastore (e.g. a database or configuration file) and implement a way to assign those properties dynamically at runtime.
But first, we need to understand what is happening when configurating a Dynamic Send Port.
How to Configure a Dynamic Logical Send Port
Configuring the properties of a dynamic logical send port from within an orchestration involves two steps:
First, the TransportType and target Address properties must be specified on the Send Port. This is usually done in an Expression Shape with code similar to this:
DynamicSendPort(Microsoft.XLANGs.BaseTypes.TransportType) = "FILE";
DynamicSendPort(Microsoft.XLANGs.BaseTypes.Address) = "C:\Temp\Folder\%SourceFileName%";
Second, any additional transport properties must be specified on the context of the outgoing message itself. Virtually all BizTalk adapters have additional properties that are used for the communication between the Messaging Engine and the XLANG/s Orchestration Engine. For instance, the ReceivedFileName context property is used to dynamically set a specific name for when the FILE adapter will save the outgoing message at its target location. This is best performed inside an Assignment Shape, as part of constructing the outgoing message:
OutgoingMessage(FILE.ReceiveFileName) = "HardCodedFileName.xml"
You'll notice that most configuration properties must be specified on the context of the outgoing messages, specifying a namespace prefix (e.g. FILE), a property name (e.g. ReceiveFileName) and, obviously, the value that gets assigned to the corresponding property.
In fact, all the context properties are classes that live Inside the well-known Microsoft.BizTalk.GlobalPropertySchemas.dll assembly. This is confirmed by looking up this assembly in Visual Studio's object explorer.
Even though most context properties that are necessary to configure Dynamic Logical Send Ports live Inside this specific assembly, not all of them do. For instance, the MSMQ BizTalk adapter uses a separate assembly to store its context properties. Obviously, third-party or custom adapters come with additionnal assemblies as well.
Therefore, in order to setup a context property on a Dynamic Send Port using a flexible approach like the one describe below, four pieces of information are necessary:
The fully qualified name of the assembly containing the context property classes.
The namespace prefix.
The property name.
The property value.
Storing Port Settings in a Persistent Medium
The following .XSD schema illustrate one possible structure for serializing port settings.
Once serialized, the specified context properties can then be stored in a SQL database or a configuration file very easily. For instance, here are the settings used as an example in this post:
A Flexible Approach to Configuring Dynamic Logical Send Ports
With a simple helper Library, setting up the dynamic port configuration is very easy. First, you have to retrieve the serialized settings from the persistent medium. This can easily be achieved using the WCF-SQL Adapter and a simple stored procedure.
Once retrieved, those properties can then be deserialized into a strongly-typed C# object graph. For this, first create a C# representation of the ContextProperties schema shown above, using the following command-line utility:
xsd.exe /classes /language:cs /namespace:Helper.Schemas .\ContextProperties.xsd
This generates a partial class that can be improved with the following method:
namespace Helper.Schemas
{
public partial class ContextProperties
{
public static ContextProperties Deserialize(string text)
{
using (MemoryStream stream = new MemoryStream())
{
byte[] buffer = Encoding.UTF8.GetBytes(text);
stream.Write(buffer, 0, buffer.Length);
stream.Seek(0, SeekOrigin.Begin);
return (ContextProperties)
Deserialize(
stream
, typeof(ContextProperties));
}
}
public static Object Deserialize(Stream stream, Type type)
{
XmlSerializer xmlSerializer = new XmlSerializer(type);
return xmlSerializer.Deserialize(stream);
}
}
}
Second, applying this configuration involves creating an XLANG/s message from code and setting up the context properties dynamically using reflection, based upon the description of the context property classes specified in the deserialized ContextProperties object graph.
For this, I use a technique borrowed from Paolo Salvatori's series of articles regarding dynamic transformations, which consists in creating a custom BTXMessage-derived class, used internally by the BizTalk XLANG/s engine.
namespace Helper.Schemas
{
using Microsoft.BizTalk.XLANGs.BTXEngine; // Found in Microsoft.XLANGs.BizTalk.Engine
using Microsoft.XLANGs.Core; // Found in Microsoft.XLANGs.Engine
[Serializable]
public sealed class CustomBTXMessage : BTXMessage
{
public CustomBTXMessage(string messageName, Context context)
: base(messageName, context)
{
context.RefMessage(this);
}
public void SetContextProperty(string assembly, string ns, string name, object value)
{
if (String.IsNullOrEmpty(ns))
ns = "Microsoft.XLANGs.BaseTypes";
if (String.IsNullOrEmpty(assembly))
assembly = "Microsoft.BizTalk.GlobalPropertySchemas";
StringBuilder assemblyQualifiedName = new StringBuilder();
assemblyQualifiedName.AppendFormat("{0}.{1}, {2}", ns, name, assembly);
Type type = Type.GetType(assemblyQualifiedName.ToString(), true, true);
SetContextProperty(type, value);
}
internal void SetContextProperty(string property, object value)
{
int index = property.IndexOf('.');
if (index != -1)
SetContextProperty(String.Empty, property.Substring(0, index), property.Substring(index + 1), value);
else
SetContextProperty(String.Empty, String.Empty, property, value);
}
}
}
Now, the last piece of the puzzle is how to make use of this custom class from within an Orchestration. This is easily done in an Assignment Shape using the following helper code:
namespace Helper.Schemas
{
using Microsoft.XLANGs.BaseTypes;
using Microsoft.XLANGs.Core; // Found in Microsoft.XLANGs.Engine
public static class Message
{
public static XLANGMessage SetContext(XLANGMessage message, ContextProperties properties)
{
try
{
// create a new XLANGMessage
CustomBTXMessage customBTXMessage = new CustomBTXMessage(message.Name, Service.RootService.XlangStore.OwningContext);
// add parts of the original message to it
for (int index = 0; index < message.Count; index++)
customBTXMessage.AddPart(message[index]);
// set the specified context properties
foreach (ContextPropertiesContextProperty property in properties.ContextProperty)
customBTXMessage.SetContextProperty(property.assembly, property.#namespace, property.name, property.Value);
return customBTXMessage.GetMessageWrapperForUserCode();
}
finally
{
message.Dispose();
}
}
}
}
You can use this static method inside your Assignment Shape like the code shown hereafter, where OutboundMessage represents the message which you want to set the context:
OutboundMessage = Helper.Schemas.Message.SetContext(OutboundMessage, contextProperties);

In the first place you shouldn't attempt to do configuration changes like this using an Orchestration. Technically it's feasible to do what you are attempting to do, but as a practice you shouldn't mix up your business process with administration.
The best way to do such things will be by either writing some normal scripts or PowerShell.
To answer you question, you can get the data you want from BtsOrchestration class in ExplorerOM
http://msdn.microsoft.com/en-us/library/microsoft.biztalk.explorerom.btsorchestration_members(v=bts.20)

Related

Manually create spring cloud stream bindings based on dynamic configuration

I have a requirement where one or more spring cloud stream kafka-streams bindings need to be created based on dynamic configuration. By dynamic config I mean stream bindings (input-output) will be specified run-time. Either via external property file or from database.
E.g We need to create multiple stream processors where input output topic pairs and relevant configs are provided. Then code should loop through this config create and start those bindings.
In spring cloud stream we write this in a java file
#StreamListener(StreamBindings.INPUT)
#SendTo(StreamBindings.OUTPUT)
public KStream<String,String> process(KStream<String,String> inputStream) {
return inputStream
.map( ... )
.selectKey( ... )
.mapValues( ... );
}
Where StreamBindings is like
public interface StreamBindings {
String INPUT = "input-topic";
String OUTPUT = "output-topic";
#Input(INPUT)
KStream<String,String> inputStream();
#Input(OUTPUT)
KStream<String,String> outputStream();
}
Now I want a piece of code to create this in run-time based on info I specified above.
Can this be done and how? And can we specify body of process function as an argument, like some kind of message handler?

CamelCase property names with NJsonSchema C# CodeGeneration

does anybody know a way to configure NJsonSchema to use CamelCase property naming durching code generation? I've a JSON schema with property names like message_id which lead to C# property name 'Message_id' where i.e. 'MessageId' whould be a more C#-like way.
With an attribute like '[JsonProperty("message_id"]' it would be no problem to specified the connection between the different names.
So, you asked about code generation. I was having trouble with the schema it generated not matching what was getting sent to my Angular app. So, while this isn't exactly what you were looking for, perhaps it helps you find an answer (maybe?).
To generate the schema with the camel case property names, I'm setting the Default Property Name Handling to CamelCase, but this is using the deprecated call to set these settings directly. There should be some way to use the SerializerSettings directly, but I wasn't quite able to make that work. This isn't production code for me, so it will do.
internal class SchemaFileBuilder<T>
{
public static void CreateSchemaFile()
{
CreateSchemaFile(typeof(T).Name);
}
public static void CreateSchemaFile(string fileName)
{
JsonSchemaGeneratorSettings settings = new JsonSchemaGeneratorSettings();
settings.DefaultPropertyNameHandling = PropertyNameHandling.CamelCase;
var schema = NJsonSchema.JsonSchema.FromType<T>(settings);
var json = schema.ToJson();
Directory.CreateDirectory("Schemas");
File.WriteAllText($"Schemas\\{fileName}.schema.json", json);
}
}
I set this up as a generic function so I could pass multiple schemas in to either createSchemaFile functions. Here's are some example calls which would generate a Person.schema.json file and a Persons.schema.json file:
SchemaFileBuilder<Person>.CreateSchemaFile();
SchemaFileBuilder<Dictionary<string, Person>>.CreateSchemaFile("Persons");

BizTalk - Fail to Promote Properties

Using BizTalk 2013r2 CU1, I have a created a property schema for my inbound xsd and deployed the application.
When I receive a sample xml document using a standard "xml receive" pipeline then I can see that the required element is promoted into the context as expected.
I then created a custom pipeline which contains the "XML disassembler" component in the "Disassemble" stage and a custom component in the "Validate" stage. This custom component needs to read the promoted property from the context. However, I find that when I switch the Receive Location from "xml receive" pipeline to my custom pipeline then my property does not get promoted. I am using the following code within my custom component to write out a list of items in the message context:
for (int x = 0; x < contextList.CountProperties; x++)
{
contextList.ReadAt(x, out name, out nspace);
string value = contextList.Read(name, nspace).ToString();
contextItems += "Name: " + name + " - " + "Namespace: " + nspace + " - " + value + "\r\n";
if (name == _ContextPropertyName && nspace == _ContextPropertyNamespace)
promotedPropFound = true;
}
Helpers.EventLogHelper eventHelper = new EventLogHelper();
eventHelper.LogEvent(string.Format("Context items:{0}", contextItems));
if (promotedPropFound == false)
throw new Exception(string.Format("Unable to find promoted property with name[{0}] and namespace [{1}]", _ContextPropertyName, _ContextPropertyNamespace));
From the output in the event log I can see that certain properties such as MessageType have been promoted but my custom property has not. Again, if I change the receive location back to use a standard "xml receive" pipeline then the property will be promoted from a copy of the same xml document (I check this by stopping the subscribing send port and viewing the context from the admin console).
I find this very strange since the same "XML disassembler" component is present in the same "Disassemble" stage of both pipelines, with the same (default)configuration. I'm starting to think perhaps there's a problem with 2013r2CU1 - has anyone else encountered the same?
By the time the XML Disassembler has executed in your custom pipeline, there is no guarantee that your properties have been promoted.
The incoming message arrives in the pipeline as a stream with the data pointer set at the start of the stream.
I think the XML Disassembler does not read the stream, it wraps it into some stream wrapper class that will populate the promoted properties when the stream actually gets read.
The stream will have to be read at least once: when the message gets inserted into the message box. So there is a guarantee that the properties will get promoted, but you cannot assume it will be done before the "Validate" stage executes.
To make sure this is really the problem your are encountering: check your message AFTER it has been imported into the message box.
If your promoted property is there, what I described is probably what is happening.
Solutions:
To make your custom pipeline component work, the best solution would be to do just as the XML Disassembler: get the incoming stream and wrap it into a stream wrapper class that can trigger whatever functionality you need.
The assembly Microsoft.BizTalk.Streaming.dll has some wrapper class that might interest you: ForwardOnlyEventingReadStream.
This class has an event AfterLastReadEvent. You can create some EventHandler and have it subscribe to this event to trigger your custom functionality only after the stream has been fully read., and all properties have been promoted.
Your custom component would look like that:
public IBaseMessage Execute(IPipelineContext context, IBaseMessage message)
{
Stream stream = message.BodyPart.GetOriginalDataStream();
CForwardOnlyEventingReadStream eventingReadStream = new CForwardOnlyEventingReadStream(stream);
eventingReadStream.AfterLastReadEvent += new AfterLastReadEventHandler(DoSomething);
message.BodyPart.Data = eventingReadStream;
return message;
}
private static void DoSomething(object src, EventArgs args)
{
}
A less efficient way to solve your problem would be to read the stream fully in your custom component at the "Validate" stage and put the stream pointer back to the start of the stream.
Microsoft has some guidelines for when you're manipulating the message stream in pipeline component:
https://msdn.microsoft.com/en-us/library/aa577699.aspx
Update:
OP needs to pass the message context to the Event Handler.
It is possible using a Lambda expression:
public IBaseMessage Execute(IPipelineContext context, IBaseMessage message)
{
Stream stream = message.BodyPart.GetOriginalDataStream();
CForwardOnlyEventingReadStream eventingReadStream = new CForwardOnlyEventingReadStream(stream);
eventingReadStream.AfterLastReadEvent += new AfterLastReadEventHandler((src, args) => DoSomething(src, args, message.Context));
message.BodyPart.Data = eventingReadStream;
return message;
}
private static void DoSomething(object src, EventArgs args, IBaseMessageContext messageContext)
{
}
This SO question can be interesting for reference for passing the additional parameter:
Pass parameter to EventHandler
Can you do whatever you had planned for the Validate Stage in an Orchestration? That would be much easier.
If not, the most common solution to this specific problem is an intermediate Pipeline Component that forces a full read on the stream, though technically, you'd only have to read until the Promoted node is hit.

WCF single vs multiple operations ?. design ideas

We are developing a CRM application. All the business logic and data access go through WCF services. We have 2 options for communication between WCF and client (at the moment: ASP.NET MVC 2)
One option is create method for each operations. Example
GetCustomers()
GetCustomersWithPaging(int take, int skip)
GetCustomersWithFilter(string filter)
GetCustomersWithFilterPaging(string filter, int take, int skip)
or // new .net 4 feature
GetCustomers(string filter = null, int take = 0, int skip = 0)
... list goes..
Another option is create a generic single service operation called
Response InvokeMessage(Messege request). Example
wcfservice.InvokeMessage(
new CustomerRequest {
Filter = "google",
Paging = new Page { take = 20, skip = 5}
});
// Service Implementation.
public Response InvokeMessage(Message request)
{
return request.InvokeMessage();
}
InvokeMessage = generic single service call for all operation.
CustomerRequest = Inherited class from Message abstract class, so I can create multiple classes from Message base class depend on the input requirements.
Here is the CustomerRequest class.
public class CustomerRequest : Message
{
public string Filter {get;set;}
public Page Paging {get;set} // Paging class not shown here.
Public override Response InvokeMessage()
{
// business logic and data access
}
}
EDIT
public abstract class Message
{
public abstract Response InvokeMessage();
}
// all service call will be through InvokeMessage method only, but with different message requests.
Basically I could avoid each service call's and proxy close etc..
One immediate implication with this approach is I cannot use this service as REST
What is the recommended approach if the service needs to call lots of methods?
thanks.
If you use the facade pattern you can have both.
First, build your services using the first option. This allows you to have a REST interface. This can be used externally if required.
You can then create a facade that uses Invoke message style, this translates the request based on the parameters and calls one of the individual services created in the first step.
As to the question of multiple specific operations vs one general query - either approach could be valid; defining fine-grained vs coarse-grained operations is to some degree a matter of taste.
When faced with a similar requirement in our RESTful service, I've chosen to create a filter class that reads parameters from the query-string, available thusly:
public NameValueCollection ReadQuerystring()
{
return WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters;
}
The larger issue that I see here is that you're subclassing Message for your operation parameters - is there a reason why you're doing that? The best practice is to create data contracts (objects annotated with [DataContract] attributes) for such a purpose.

Access SQLite from different processes

I'm developing an application that uses SQLite as the primary data storage method. I have two processes running for my app using an alternate entry point.
I need to access the same DB from the two different processes but as we all now SQLite is not like a server DB engine, it can only be accessed once at a time.
I wanted to know if there is a way to kind of "lock" the DB when it's being accessed by other process so that if the second process tries to acces the DB at the same time, it would wait until the first process finishes and then try to access it again.
How can this issue be treated?
If you have not already, create a class that abstracts your database access out and store it in the RuntimeStore. From wherever you are going to interface with SQLite, get a reference to that class using the GUID you stored it with (RuntimeStore.get(long)) and synchronize the class however you would normally (member object lock, synchronized methods).
Do NOT just use the Wikipedia style singleton pattern as it is not a true singleton across processes on this platform.
See:
http://www.blackberry.com/developers/docs/5.0.0api/net/rim/device/api/system/RuntimeStore.html
Sample:
class SQLManager {
private static long GUID = 0xa178d3ce564cae69L; // hash of com.stackoverflow.SQLManager
private SQLManager() {
// ctor stuff here
}
public static SQLManager getInstance() {
RuntimeStore rs = RuntimeStore.getRuntimeStore();
SQLManager instance = rs.get(GUID);
if (instance == null) {
instance = new SQLManager();
rs.put(GUID, instance);
}
return instance;
}
}
You're still using the singleton "pattern" per se, but you're storing the object instance in the RuntimeStore on first getInstance call, and subsequently pulling it form the RuntimeStore - using a GUID that you specify.

Resources