I'm working on a biztalk project and use a map to create the new message.
Now i want to map a datefield to a string.
I thought i can do it on this way with an Function Script with inline C#
public string convertDateTime(DateTime param)
{
return System.Xml.XmlConvert.ToString(param,ÿyyyMMdd");
}
But this doesn't work and i receive an error. How can i do the convert in the map?
It's a Biztalk 2006 project.
Without the details of the error you are seeing it is hard to be sure but I'm quite sure that your map is failing because all the parameters within the BizTalk XSLT engine are passed as strings1.
When I try to run something like the function you provided as inline C# I get the following error:
Object of type 'System.String' cannot be converted to type 'System.DateTime'
Replace your inline C# with something like the following:
public string ConvertDateTime(string param1)
{
DateTime inputDate = DateTime.Parse(param1);
return inputDate.ToString("yyyyMMdd");
}
Note that the parameter type is now string, and you can then convert that to a DateTime and perform your string format.
As other answers have suggested, it may be better to put this helper method into an external class - that way you can get your code under test to deal with edge cases, and you also get some reuse.
1 The fact that all parameters in the BizTalk XSLT are strings can be the source of a lot of gotchas - one other common one is with math calculations. If you return numeric values from your scripting functoids BizTalk will helpfully convert them to strings to map them to the outbound schema but will not so helpfully perform some very random rounding on the resulting values. Converting the return values to strings yourself within the C# will remove this risk and give you the expected results.
If you're using the mapper, you just need a Scripting Functiod (yes, using inline C#) and you should be able to do:
public string convertDateTime(DateTime param)
{
return(param.ToString("YYYYMMdd");
}
As far as I know, you don't need to call the System.Xml namespace in anyway.
I'd suggest
public static string DateToString(DateTime dateValue)
{
return String.Format("{0:yyyyMMdd}", dateValue);
}
You could also create a external Lib which would provide more flexibility and reusability:
public static string DateToString(DateTime dateValue, string formatPicture)
{
string format = formatPicture;
if (IsNullOrEmptyString(formatPicture)
{
format = "{0:yyyyMMdd}";
}
return String.Format(format, dateValue);
}
public static string DateToString(DateTime dateValue)
{
return DateToString(dateValue, null);
}
I tend to move every function I use twice inside an inline script into an external lib. Iit will give you well tested code for all edge cases your data may provide because it's eays to create tests for these external lib functions whereas it's hard to do good testing on inline scripts in maps.
This blog will solve your problem.
http://biztalkorchestration.blogspot.in/2014/07/convert-datetime-format-to-string-in.html?view=sidebar
Regards,
AboorvaRaja
Bangalore
+918123339872
Given that maps in BizTalk are implemented as XSL stylesheets, when passing data into a msxsl scripting function, note that the data will be one of types in the Equivalent .NET Framework Class (Types) from this table here. You'll note that System.DateTime isn't on the list.
For parsing of xs:dateTimes, I've generally obtained the /text() node and then parse the parameter from System.String:
<CreateDate>
<xsl:value-of select="userCSharp:GetDateyyyyMMdd(string(s0:StatusIdChangeDate/text()))" />
</CreateDate>
And then the C# script
<msxsl:script language="C#" implements-prefix="userCSharp">
<![CDATA[
public System.String GetDateyyyyMMdd(System.String p_DateTime)
{
return System.DateTime.Parse(p_DateTime).ToString("yyyyMMdd");
}
]]>
Related
I have a pipeline that successfully outputs an Avro file as follows:
#DefaultCoder(AvroCoder.class)
class MyOutput_T_S {
T foo;
S bar;
Boolean baz;
public MyOutput_T_S() {}
}
#DefaultCoder(AvroCoder.class)
class T {
String id;
public T() {}
}
#DefaultCoder(AvroCoder.class)
class S {
String id;
public S() {}
}
...
PCollection<MyOutput_T_S> output = input.apply(myTransform);
output.apply(AvroIO.Write.to("/out").withSchema(MyOutput_T_S.class));
How can I reproduce this exact behavior except with a parameterized output MyOutput<T, S> (where T and S are both Avro code-able using reflection).
The main issue is that Avro reflection doesn't work for parameterized types. So based on these responses:
Setting Custom Coders & Handling Parameterized types
Using Avrocoder for Custom Types with Generics
1) I think I need to write a custom CoderFactory but, I am having difficulty figuring out exactly how this works (I'm having trouble finding examples). Oddly enough, a completely naive coder factory appears to let me run the pipeline and inspect proper output using DataflowAssert:
cr.RegisterCoder(MyOutput.class, new CoderFactory() {
#Override
public Coder<?> create(List<? excents Coder<?>> componentCoders) {
Schema schema = new Schema.Parser().parse("{\"type\":\"record\,"
+ "\"name\":\"MyOutput\","
+ "\"namespace\":\"mypackage"\","
+ "\"fields\":[]}"
return AvroCoder.of(MyOutput.class, schema);
}
#Override
public List<Object> getInstanceComponents(Object value) {
MyOutput<Object, Object> myOutput = (MyOutput<Object, Object>) value;
List components = new ArrayList();
return components;
}
While I can successfully assert against the output now, I expect this will not cut it for writing to a file. I haven't figured out how I'm supposed to use the provided componentCoders to generate the correct schema and if I try to just shove the schema of T or S into fields I get:
java.lang.IllegalArgumentException: Unable to get field id from class null
2) Assuming I figure out how to encode MyOutput. What do I pass to AvroIO.Write.withSchema? If I pass either MyOutput.class or the schema I get type mismatch errors.
I think there are two questions (correct me if I am wrong):
How do I enable the coder registry to provide coders for various parameterizations of MyOutput<T, S>?
How do I values of MyOutput<T, S> to a file using AvroIO.Write.
The first question is to be solved by registering a CoderFactory as in the linked question you found.
Your naive coder is probably allowing you to run the pipeline without issues because serialization is being optimized away. Certainly an Avro schema with no fields will result in those fields being dropped in a serialization+deserialization round trip.
But assuming you fill in the schema with the fields, your approach to CoderFactory#create looks right. I don't know the exact cause of the message java.lang.IllegalArgumentException: Unable to get field id from class null, but the call to AvroCoder.of(MyOutput.class, schema) should work, for an appropriately assembled schema. If there is an issue with this, more details (such as the rest of the stack track) would be helpful.
However, your override of CoderFactory#getInstanceComponents should return a list of values, one per type parameter of MyOutput. Like so:
#Override
public List<Object> getInstanceComponents(Object value) {
MyOutput<Object, Object> myOutput = (MyOutput<Object, Object>) value;
return ImmutableList.of(myOutput.foo, myOutput.bar);
}
The second question can be answered using some of the same support code as the first, but otherwise is independent. AvroIO.Write.withSchema always explicitly uses the provided schema. It does use AvroCoder under the hood, but this is actually an implementation detail. Providing a compatible schema is all that is necessary - such a schema will have to be composed for each value of T and S for which you want to output MyOutput<T, S>.
Is there any way to conditionally import libraries / code based on environment flags or target platforms in Dart? I'm trying to switch out between dart:io's ZLibDecoder / ZLibEncoder classes and zlib.js based on the target platform.
There is an article that describes how to create a unified interface, but I'm unable to visualize that technique not creating duplicate code and redundant tests to test that duplicate code. game_loop employs this technique, but uses separate classes (GameLoopHtml and GameLoopIsolate) that don't seem to share anything.
My code looks a bit like this:
class Parser {
Layer parse(String data) {
List<int> rawBytes = /* ... */;
/* stuff you don't care about */
return new Layer(_inflateBytes(rawBytes));
}
String _inflateBytes(List<int> bytes) {
// Uses ZLibEncoder on dartvm, zlib.js in browser
}
}
I'd like to avoid duplicating code by having two separate classes -- ParserHtml and ParserServer -- that implement everything identically except for _inflateBytes.
EDIT: concrete example here: https://github.com/radicaled/citadel/blob/master/lib/tilemap/parser.dart. It's a TMX (Tile Map XML) parser.
You could use mirrors (reflection) to solve this problem. The pub package path is using reflection to access dart:io on the standalone VM or dart:html in the browser.
The source is located here. The good thing is, that they use #MirrorsUsed, so only the required classes are included for the mirrors api. In my opinion the code is documented very good, it should be easy to adopt the solution for your code.
Start at the getters _io and _html (stating at line 72), they show that you can load a library without that they are available on your type of the VM. Loading just returns false if the library it isn't available.
/// If we're running in the server-side Dart VM, this will return a
/// [LibraryMirror] that gives access to the `dart:io` library.
///
/// If `dart:io` is not available, this returns null.
LibraryMirror get _io => currentMirrorSystem().libraries[Uri.parse('dart:io')];
// TODO(nweiz): when issue 6490 or 6943 are fixed, make this work under dart2js.
/// If we're running in Dartium, this will return a [LibraryMirror] that gives
/// access to the `dart:html` library.
///
/// If `dart:html` is not available, this returns null.
LibraryMirror get _html =>
currentMirrorSystem().libraries[Uri.parse('dart:html')];
Later you can use mirrors to invoke methods or getters. See the getter current (starting at line 86) for an example implementation.
/// Gets the path to the current working directory.
///
/// In the browser, this means the current URL. When using dart2js, this
/// currently returns `.` due to technical constraints. In the future, it will
/// return the current URL.
String get current {
if (_io != null) {
return _io.classes[#Directory].getField(#current).reflectee.path;
} else if (_html != null) {
return _html.getField(#window).reflectee.location.href;
} else {
return '.';
}
}
As you see in the comments, this only works in the Dart VM at the moment. After issue 6490 is solved, it should work in Dart2Js, too. This may means that this solution isn't applicable for you at the moment, but would be a solution later.
The issue 6943 could also be helpful, but describes another solution that is not implemented yet.
Conditional imports are possible based on the presence of dart:html or dart:io, see for example the import statements of resource_loader.dart in package:resource.
I'm not yet sure how to do an import conditional on being on the Flutter platform.
I have a requirement to send an object as xml to a webservice. I already have the pojo, now I need to convert it to xml using Groovy. In grails I have used the as keyword, what is the equivalent code to do this in Groovy?
Example Grails code:
import grails.converters.*
render Airport.findByIata(params.iata) as XML
A naive example of doing this with StreamingMarkupBuilder would be:
class Airport {
String name
String code
int id
}
Writable pogoToXml( object ) {
new groovy.xml.StreamingMarkupBuilder().bind {
"${object.getClass().name}" {
object.getClass().declaredFields.grep { !it.synthetic }.name.each { n ->
"$n"( object."$n" )
}
}
}
}
println pogoToXml( new Airport( name:'Manchester', code:'MAN', id:1 ) )
Which should print:
<Airport><name>Manchester</name><code>MAN</code><id>1</id></Airport>
The as keyword is actually part of the Groovy language spec. The part you are missing is the XML class that does the conversion. This is really just a fancy class that walks the POJO and writes the XML (possibly using MarkupBuilder).
Groovy does not have a built-in class like grails.converters.XML that makes it so easy. Instead, you'll need to manually build the XML using MarkupBuilder or StreamingMarkupBuilder.
Neither of these will automatically convert a POJO or POGO to XML, you'll have to either process this yourself manually, or use reflection to automate the process.
I'd suggest that you might be able to copy the grails converter over, but it may have a lot of dependencies. Still, it's open source, that might be a starting point if you need a more reusable component.
I'm writing a CLR stored procedure to take XML data in the form of a string, then use the data to execute certain commands etc.
The problem that I'm running into is that whenever I try to send XML that is longer than 4000 characters, I get an error, as the XmlDocument object can't load the XML as a lot of the closing tags are missing, due to the text being truncated after 4000 chars.
I think this problem boils down to the CLR stored procedure mapping the string parameter onto nvarchar(4000), when I'm thinking something like nvarchar(max) or ntext would be what I need.
Unfortunately, I can't find a mapping from a .NET type onto ntext, and the string type automatically goes to nvarchar(max).
Does anyone know of a solution to my problem?
Thanks for any help
I think you want the System.Data.SqlTypes.SqlXml type.
For example:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;
using Microsoft.SqlServer.Server;
public partial class StoredProcedures
{
[SqlProcedure]
public static void StoredProcedure1(SqlXml data)
{
using (XmlReader reader = data.CreateReader())
{
reader.MoveToContent();
// Do stuff here.
}
}
};
For CLR stored procedures, char, varchar, text, ntext, image, cursor,
user-define table types and table cannot be specified as parameters.
You should be able the nvarchar(max) type instead of the ntext type.
ntext will disappear in future versions of SQL Server so you should use nvarchar(MAX) instead.
I have a versioned model:
public class VersionedModel
{
public Binary Version { get; set; }
}
Rendered using
<%= Html.Hidden("Version") %>
it gives:
<input id="Version" name="Version" type="hidden" value=""AQID"" />
that looks a bit strange. Any way, when the form submitted, the Version field is always null.
public ActionResult VersionedUpdate(VersionedModel data)
{
...
}
How can I pass Version over the wire?
EDIT:
A naive solution is:
public ActionResult VersionedUpdate(VersionedModel data)
{
data.Version = GetBinaryValue("Version");
}
private Binary GetBinaryValue(string name)
{
return new Binary(Convert.FromBase64String(this.Request[name].Replace("\"", "")));
}
Related posts I found.
Link
Suggests to turn 'Binary Version' into 'byte[] Version', but some commenter noticed:
The problem with this approach is that
it doesn't work if you want to use the
Table.Attach(modified, original)
overload, such as when you are using a
disconnected data context.
Link
Suggests a solution similar to my 'naive solution'
public static string TimestampToString(this System.Data.Linq.Binary binary)
{ ... }
public static System.Data.Linq.Binary StringToTimestamp(this string s)
{ ... }
http://msdn.microsoft.com/en-us/library/system.data.linq.binary.aspx
If you are using ASP.Net and use the
SQL Server "timestamp" datatype for
concurrency, you may want to convert
the "timestamp" value into a string so
you can store it (e.g., on a web
page). When LINQ to SQL retrieves a
"timestamp" from SQL Server, it stores
it in a Binary class instance. So you
essentially need to convert the Binary
instance to a string and then be able
to convert the string to an equivalent
Binary instance.
The code below provides two extension
methods to do this. You can remove the
"this" before the first parameter if
you prefer them to be ordinary static
methods. The conversion to base 64 is
a precaution to ensure that the
resultant string contains only
displayable characters and no escape
characters.
public static string ConvertRowVersionToString(this Binary rowVersion) {
return Convert.ToBase64String(rowVersion.ToArray());
}
public static Binary ConvertStringToRowVersion(this string rowVersion) {
return new Binary(Convert.FromBase64String(rowVersion));
}
I think the problem with not seeing it in the bound model on form submission is that there is no Convert.ToBinary() method available to the model binary to restructure the data from a string to it's binary representation. If you want to do this, I think that you'll need to convert the value by hand. I'm going to guess that the value you are seeing is the Base64 encoding of the binary value -- the output of Binary.ToString(). In that case, you'll need to convert it back from Base64 to a byte array and pass that to the Binary() constructor to reconstitute the value.
Have you thought about caching the object server-side, instead? This could be a little tricky as well as you have to detach the object from the data context (I'm assuming LINQ) or you wouldn't be able to reattach it to a different data context. This blog entry may be helpful if you decide to go that route.
You may need to use binding to get a strongly-typed parameter to your action method.
Try rendering using:
<%=Html.Hidden("VersionModel.Version")%>
And defining your action method signature as:
public ActionResult VersionedUpdate([Bind(Prefix="VersionModel")] VersionedModel data)
{
...
}
This post http://forums.asp.net/p/1401113/3032737.aspx#3032737 suggests to use
LinqBinaryModelBinder from http://aspnet.codeplex.com/SourceControl/changeset/view/21528#338524.
Once registered
protected void Application_Start()
{
ModelBinders.Binders.Add(typeof(Binary), new LinqBinaryModelBinder());
}
the binder will automatically deserialize Version field
public ActionResult VersionedUpdate(VersionedModel data)
{ ... }
rendered this way:
<%= Html.Hidden("Version") %>
(See also http://stephenwalther.com/blog/archive/2009/02/25/asp.net-mvc-tip-49-use-the-linqbinarymodelbinder-in-your.aspx)
There are many ways like here
byte[] b = BitConverter.GetBytes(DateTime.Now.Ticks);//new byte [(DateTime.Now).Ticks];
_store.Version = new System.Data.Linq.Binary(b)
(make sure you bind exclude your version),
But the best way is to let the DB handle it...
There are many ways like here
byte[] b = BitConverter.GetBytes(DateTime.Now.Ticks);//new byte [(DateTime.Now).Ticks]; _store.Version = new System.Data.Linq.Binary(b)
(make sure you bind exclude your version),
But the best way is to let the DB handle it...