摘要: Biztalk 2006 R2中使用集成的EDI Outbound Batching能够很容易地实现打包发送EDI文档的功能。 以下是在EDI Outbound Batching中起重要作用的4个Promoted Context: EDI.ToBeBatched EDI.ToBeRouted EDI.DestinationPartyID EDI.EncodingType 以及集成在Biztalk EDI Application中的3个Orchestration Microsoft.BizTalk.Edi.BatchSuspendOrchestration.BatchElementSuspendService Microsoft.BizTalk.Edi.BatchingOrchestration.Ba  阅读全文
posted @ 2008-08-19 23:35 Andre 阅读(93) | 评论 (0)编辑

以下是Biztalk EDI X12文件的schema中使用到各种数据类型:

X12_N   - 数字类型(integer)

X12_R   - 实数类型(real)。 格式为 [sign]integral-digits[.[fractional-digits]], Sign(符号)只能是“-”,不允许是“+”
注意:
在VS2005 IDE中使用shema来验证xml实例,若该类型的节点内容前后带有数字"0"或着空格时(如12.20, 005),会出现类似以下的错误提示
Error 16 Segment level  : Field Error : Segment ID - MEA : Field Position - 3 : Current value - 12.20 : [6] Invalid character in data element
这种xml实例无论如何也通不过shema验证,
不过只要在Party的EDI属性X12 Properties -> Party as Interchage Sender -> ACK Generation and Validation Settings中,
将Allow leading and trailing zeros and spaces复选框勾上,那么在EDI pipeline进行解析的运行时就可以让这种xml通过验证了


X12_AN - 字符或数字类型(alphanumeric)

X12_ID  - 枚举类型

X12_DT - 日期类型(DateTime)

X12_TM - 时间类型(Time)

X12_Nx - 指定了小数位的数字类型。x > 0,假如设定为"N2",则代表x12文件经过pipeline解析后数值1234会转换为12.34
注意:
激活自动转换的功能需要在Party的EDI属性X12 Properties -> Party as Interchage Sender -> ACK Generation and Validation Settings中,
将Convert implied decimal format Nn to base 10 numeric value复选框勾上


--其实着以上类型都与ANSI EDI X12文档的标准类型定义是一致的

posted @ 2008-06-14 21:35 Andre 阅读(48) | 评论 (0)编辑
     摘要: 最近写了一段自定义的ConfigurationSection继承类,通过该class可以轻松得定义和读取配置文件信息,注意这里使用的是c# 2.0来实现的,相比1.1必须通过实现IConfigurationSectionHandler接口来自定义配置节点类方便多了不论是web.config还是app.config,都可以使用ConfigurationManager类加载配置文件中自定义的节点内容。... 阅读全文
posted @ 2008-01-02 23:23 Andre 阅读(603) | 评论 (3)编辑
对于数字系统中进制间的转换,堆栈无疑是最好的选择,也是最能体现堆栈好处的地方。

以下是我用C#写的一个简单实现十进制数向2,8,16进制间的转换:
(当然,CLR还有更简单的方法,那就是Convert.ToString(int value, int toBase),value是需要转换的十进制数,toBase是将要转换的进制类型,2, 8或16进制)


namespace CRLDemo
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            
try
            
{
                NumberSystemUtil.ConvertDecimal(
31, Scale.Hexadecimal);
                
//Console.WriteLine(Convert.ToString(31, 16));
            }

            
catch (Exception ex)
            
{
                Console.WriteLine(ex.Message);
            }

            
finally
            
{
                Console.ReadLine();
            }

        }

    }


    
public class NumberSystemUtil
    

        
public static void ConvertDecimal(int dec, Scale scale)
        
{
            Stack
<int> stack = new Stack<int>();

            
while (dec > 0)
            
{
                stack.Push(dec 
% (int)scale);
                dec 
= dec / (int)scale;
            }


            
while (stack.Count > 0)
            
{
                
if (scale == Scale.Hexadecimal)
                    Console.Write(stack.Pop().ToString(
"x"));
                
else
                    Console.Write(stack.Pop());
            }

        }

    }


    
public enum Scale
    
{
        Hexadecimal 
= 16,
        Octal 
= 8,
        Binary 
= 2
    }

}
posted @ 2007-09-24 10:05 Andre 阅读(192) | 评论 (1)编辑

一个超级恶搞的网站: http://www.msfirefox.com/

从界面上看,这个网站从头到尾还真跟微软官方网站差不多,不但MSFirefox介绍板块模仿IE7的,就连网址前的小图标、版权声明都没有放过,细心程度可见一斑。整个网站功能齐全,各种分类项目都非常详细,真是……有功夫啊。

根据这个网站的“新闻稿”,Firefox的Luva69已经被炒鱿鱼,由微软CEO鲍尔默取而代之,Firefox也成为微软的一个部门,并推举比尔·盖茨担任总裁、联合主席和副总裁。

如果这还不算什么,就看看“整合”了Firefox和IE的新浏览器吧。MSFirefox重点提供“Cut Away Effect”(砍掉特效)功能,可以随机屏蔽一个网页90%的渲染效果,从而节省系统资源,同时还能将屏幕面积最大程度地让给桌面,让你更轻松地执行日常任务。

MSFirefox同样支持RSS,不过这里代表的是——“Real Simple Sex”。该网站声称这是一种新的算法技术,是很多网民梦寐以求的东西。网站大摇大摆地详细吹捧了这种技术,这里就不赘述了。

还有效仿Windows Defender和PatchGuard的“TakeOver”防护技术,可以抵挡各种恶意程序,比如赛门铁克的、McAfee的、Kaspersky的、趋势的等等。另外,MSFirefox的父母控制技术可以让孩子们只能访问微软网站。全部“特色”介绍在这里。

该网站还提供了MSFirefox的下载,不过如果你真的去点击,想付费30美元看看这个需要4.6GHz主频四核心处理器、微软键鼠套装、512MB显存显卡、HD DVD光驱,甚至计划支持Linux的新浏览器,最后得到的是IE7。

在网站首页底部,还恶搞了一把Adobe Flash和Windows Media Player:微软推出Microsoft Akboe Phlash,让您尽情欣赏照片、音乐和视频。

--摘自http://news1.mydrivers.com/pages/20061110110950_42425.htm

posted @ 2006-11-11 08:33 Andre 阅读(89) | 评论 (0)编辑

    前段时间在使用DAAB(Data Access Application Block) 2.0中的SqlHelper对象来做数据填充,因为2.0版本的SqlHelper里多了一个FillDataset方法很好使,特别是在你想使用存储过程一次性返回多个数据表时非常有用,它的一个重载方法中可以传入一个string[]类型的表名列表。但是在填充数据集的过程中,发现只要数据集中的表大于三张时老是会出问题,开始以为是自己的强类型数据集的字段类型或者字段个数与存储过程中取出的各个表的字段不一致,但是经过仔细检查并没有发现任何问题。这我就纳闷了,使用SqlHelper.FillDataset方法来填充三个表中的任意两个都没有问题,怎么多一个就出问题了?于是我把取出的结果集全部展开来看了一下,这才发现居然多了一个名为"Table2"的表,也就是说通过SqlHelper对象读出的表有四个,且第三个表被挤到了第四的位置,而且表三的内容居然也已经填充正确了,只不过表三的表名成了"Table2"!

我这下意识到应该是SqlHelper的问题了,于是我找到FillDataset的最后一个重载方法(SqlHelper.cs文件物理位置的最后一个):

private static void FillDataset(SqlConnection connection, SqlTransaction transaction, CommandType commandType, 
            
string commandText, DataSet dataSet, string[] tableNames,
            
params SqlParameter[] commandParameters)
        
{
            
if( connection == null ) throw new ArgumentNullException( "connection" );
            
if( dataSet == null ) throw new ArgumentNullException( "dataSet" );

            
// Create a command and prepare it for execution
            SqlCommand command = new SqlCommand();
            
bool mustCloseConnection = false;
            PrepareCommand(command, connection, transaction, commandType, commandText, commandParameters, 
out mustCloseConnection );
                
            
// Create the DataAdapter & DataSet
            using( SqlDataAdapter dataAdapter = new SqlDataAdapter(command) )
            
{
                
                
// Add the table mappings specified by the user
                if (tableNames != null && tableNames.Length > 0)
                
{
                    
string tableName = "Table";
                    
for (int index=0; index < tableNames.Length; index++)
                    
{
                        if( tableNames[index] == null || tableNames[index].Length == 0 ) throw new ArgumentException( "The tableNames parameter must contain a list of tables, a value was provided as null or empty string.", "tableNames" );
                        dataAdapter.TableMappings.Add(tableName, tableNames[index]);
                        tableName += (index + 1).ToString();
                    }
                }

                
                
// Fill the DataSet using default values for DataTable names, etc
                dataAdapter.Fill(dataSet);

                
// Detach the SqlParameters from the command object, so they can be used again
                command.Parameters.Clear();
            }


            
if( mustCloseConnection )
                connection.Close();
        }


请注意那段红色的语句:
tableName += (index + 1).ToString();
大家只要看一眼就明白了吧,这是一个很明显的bug! 当我们有两张表时,DataAdaper在做表名映射时就很正常,因为此时的两张表的tableName分别为Table和Table1, 但是再加上一张表或更多的话, 那tableName就成了Table12, Table123, Table1234, ...如此这般, 后果将不堪设想。怪不得我的结果数据集里面会多一张Table2出来,原来Table2根本就没有映射到我的强类型数据集的第三张表上来。

那么既然发现了bug,我们就得手工改正一下了,其实很简单,只需要将那段语句改为:
tableName = "Table" + (index + 1).ToString();
这样就一切OK了。

不知道MS现在是否已经修复了DAAB2.0里的这个bug,但至少我上个月才下载的这个版本里还存在有。

posted @ 2006-08-14 10:28 Andre 阅读(614) | 评论 (1)编辑
今天晚上就是世界杯开幕式了,好兴奋!!

大家一定都听说过Google和Nike联办了一个Blog网站,网址是www.joga.com,专门提供给足球爱好者进行交流,
由nike提供娱乐内容,google提供网站搭建平台,
就算你没听说过,但至少你可能也看过该网站的广告吧,只是可能没太在意,
实际上nike最近的世界杯系列广告中充斥了joga网站的logo



Joga的帮助中这样写道:
Joga 是 Google 和 Nike 为世界各地用户创建的在线社区,在这里,人们可以分享对足球这一全球最流行运动的热爱。在 Joga ,您可以结识同道球迷、组织赛事和俱乐部、访问 Nike 提供的运动员资料、欣赏视频剪辑和照片(您甚至可以上传自己的视频和照片)。您可以巩固友情,结交新知,加入各种各样的职业运动员和球队社区,甚至创建自己的社区,讨论球员、交流最酷的动作的技巧、遍览世界各地各个赛场并安排今后的赛事。

由于我们.net俱乐部的基本都是搞微软技术的,也许多少会对Google有些反感,因为它是微软目前最大的竞争对手,
不过在你登录了joga后,你会惊奇地发现它是由asp.net搭建的,也就是说,提供技术方案的google竟然采用的是asp.net架构!
不知道这是nike作的决定还是google作的决定,但至少证明google的开发团队中还是有搞.net的,
可能是.net技术的成熟度和快速开发能力打动了google吧
posted @ 2006-06-09 16:18 Andre 阅读(76) | 评论 (0)编辑

相信数组是大家在编程最常使用的,不论任何语言都存在数组这样的数据结构,由于C#语言是完全面向对象的,所以在C#中的数组也是对象,
实际上就是Array类的实例,Array类的使用可以说是使用最频繁的,只是大家在使用时都没太在意,如在创建数组int[]时实际上就创建了一个Array类对象的实例。
最近我仔细研究了一下C#中的Array及ArrayList类之间的异同,总结了以下几点:

[Array和ArrayList的区别]

#1. Array类型的变量在声明的同时必须进行实例化(至少得初始化数组的大小),而ArrayList可以只是先声明。
如:
 int[] array = new array[3];
 或 int[] array = {1,2,3};
 或 ArrayList myList = new ArrayList();
这些都是合法的,而直接使用 int[] array;是不行的。

#2. Array只能存储同构的对象,而ArrayList可以存储异构的对象。
同构的对象是指类型相同的对象,若声明为int[]的数组就只能存放整形数据,string[]只能存放字符型数据,但声明为object[]的数组除外。
而ArrayList可以存放任何不同类型的数据(因为它里面存放的都是被装箱了的Object型对象,实际上ArrayList内部就是使用"object[] _items;"这样一个私有字段来封装对象的)

#3 在CLR托管对中的存放方式
Array是始终是连续存放的,而ArrayList的存放不一定连续。

#4 初始化大小
Array对象的初始化必须只定指定大小,且创建后的数组大小是固定的,
而ArrayList的大小可以动态指定,其大小可以在初始化时指定,也可以不指定,也就是说该对象的空间可以任意增加。

#5 Array不能够随意添加和删除其中的项,而ArrayList可以在任意位置插入和删除项。


[Array和ArrayList的相似点]

#1 都具有索引(index),即可以通过index来直接获取和修改任意项。
#2 他们所创建的对象都放在托管堆中。
#3 都能够对自身进行枚举(因为都实现了IEnumerable接口)。


[ArrayList的一些特性]

#1 在研究ArrayList我发现了一个有趣的现象,ArrayList的capacity属性值会随ArrayList中的项的实际大小来发生改变,
如下代码:

public static void Main(string[] args)
        
{
            ArrayList myList 
= new ArrayList(2);
            Console.WriteLine(
"initial capacity:" + myList.Capacity);

            
int size = 2;
            
for (int i = 0; i < size;i++ )
            
{
                myList.Add(i);
            }

            Console.WriteLine(
"current capacity:" + myList.Capacity);
            
            Console.ReadLine();
        }

当size为2时,输出结果中的"current capacity"为2,
当size为3或4时,"current capacity"为4,
当size为5~8时,"current capacity"为8,
当size为9~16时,"current capacity"为16,
...
通过实验可以得出一个结论,那就是每当ArrayList中的实际存在的对象数(ArrayList.Count)超过了自身的Capacity阀值,那么该阀值会自动翻倍。
(也可以改变myList生成时的初始值来试试,但结论是一样的)

#2 通过ArrayList类的TrimToResize()方法可以将ArrayList实例中的空项去除以压缩体积。
如以下代码:

public static void Main(string[] args)
        
{
            ArrayList myList 
= new ArrayList(5);

            
for (int i = 0; i < 3; i++)
            
{
                myList.Add(i);
            }

            Console.WriteLine(
"actual capacity:" + myList.Capacity);
            myList.TrimToSize();
            Console.WriteLine(
"compressed capacity:" + myList.Capacity);
            
            Console.ReadLine();
        }

输出:
actual capacity:5
compressed capacity:3

#3 在C#2.0中,建议大家尽量使用范型版的ArrayList,即System.Collection.Generics命名空间下的List<T>,
这样不但保证了类型安全,而且由于没有了装箱和拆箱的过程,从而提高了对象处理的效率。

 

posted @ 2006-05-31 00:08 Andre 阅读(2304) | 评论 (2)编辑
     摘要: 终于翻完了第四篇,本来每次都是周末发的,可惜上周末有些事儿没忙过来,所以今天中午给补上来。不知道这套文章还能不能继续了,因为作者也只写到了第四篇,连他都不知道第五篇什么时候出得来...原文出处http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory_401282006141834PM/csharp_memory_4.aspx可以... 阅读全文
posted @ 2006-05-29 14:02 Andre 阅读(666) | 评论 (2)编辑

原文出处
http://www.c-sharpcorner.com/UploadFile/rmcochran/chsarp_memory401152006094206AM/chsarp_memory4.aspx

尽管在.NET framework下我们并不需要担心内存管理和垃圾回收(Garbage Collection),但是我们还是应该了解它们,以优化我们的应用程序。同时,还需要具备一些基础的内存管理工作机制的知识,这样能够有助于解释我们日常程序编写中的变量的行为。在本文中我们将涉及到堆中引用变量引起的问题,以及如何使用ICloneable接口来解决该问题。

需要回顾堆栈基础,值类型和引用类型,请转到第一部分第二部分



* 副本并不是真的副本

为了清楚的阐明问题,让我们来比较一下当堆中存在值类型和引用类型时都发生了些什么。首先来看看值类型,如下面的类和结构。这里有一个类Dude,它的成员中有一个string型的Name字段及两个Shoe类型的字段--RightShoe、LeftShoe,还有一个CopyDude()方法可以很容易地生成新的Dude实例。

           public struct Shoe{

               public string Color;

           }

 

           public class Dude

           {

                public string Name;

                public Shoe RightShoe;

                public Shoe LeftShoe;

 

                public Dude CopyDude()

                {

                    Dude newPerson = new Dude();

                     newPerson.Name = Name;

                     newPerson.LeftShoe = LeftShoe;

                     newPerson.RightShoe = RightShoe;

 

                     return newPerson;

                }

 

                public override string ToString()

                {

                     return (Name + " : Dude!, I have a " + RightShoe.Color  +

                         " shoe on my right foot, and a " +

                          LeftShoe.Color + " on my left foot.");

                }

 

           }

Dude是引用类型,而且由于结构Shoe的两个字段是Dude类的成员,所以它们都被放在了堆上。

当我们执行以下的方法时:

           public static void Main()

           {

               Class1 pgm = new Class1();

                  Dude Bill = new Dude();

                  Bill.Name = "Bill";

                  Bill.LeftShoe = new Shoe();

                  Bill.RightShoe = new Shoe();

                  Bill.LeftShoe.Color = Bill.RightShoe.Color = "Blue";


                  Dude Ted =  Bill.CopyDude();

                  Ted.Name = "Ted";

                  Ted.LeftShoe.Color = Ted.RightShoe.Color = "Red";

 
                  Console.WriteLine(Bill.ToString());

                  Console.WriteLine(Ted.ToString());            

 

           }

我们得到了预期的结果:

Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot.
Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot.

如果我们将结构Shoe换成引用类型会发生什么?问题就在于此。
假如我们将Shoe改为引用类型:

           public class Shoe{

               public string Color;

           }

然后在与前面相同的Main()方法中运行,再来看看我们的结果:

Bill : Dude!, I have a Red shoe on my right foot, and a Red on my left foot
Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot

可以看到红鞋子被穿到别人(Bill)脚上了,很明显出错了。你想知道这是为什么吗?我们再来看看堆就明白了。

由于我们现在使用的Shoe是引用类型而非值类型,当引用类型的内容被拷贝时实际上只拷贝了该类型的指针(并没有拷贝实际的对象),我们需要作一些额外的工作来使我们的引用类型能够像值类型一样使用。

幸运的是.NET Framework中已经有了一个IClonealbe接口(System.ICloneable)来帮助我们解决问题。使用这个接口可以规定所有的Dude类必须遵守和定义引用类型应如何被复制,以避免出现"共享鞋子"的问题。所有需要被克隆的类都需要使用ICloneable接口,包括Shoe类。

System.IClonealbe只有一个方法定义:Clone()

                  public object Clone()

                  {

                  }

我们应该在Shoe类中这样实现:

           public class Shoe : ICloneable

             {

                  public string Color;

                  #region ICloneable Members

                  public object Clone()

                  {

                      Shoe newShoe = new Shoe();

                      newShoe.Color = Color.Clone() as string;

                      return newShoe;

                  }

                  #endregion

             }

在方法Clone()中,我们创建了一个新的Shoe对象,克隆了所有引用类型,并拷贝了所有值类型,然后返回了这个新对象。你可能注意到了string类已经实现了ICloneable接口,所以我们可以直接调用Color.Clone()方法。因为Clone()方法返回的是对象的引用,所以我们需要在设置鞋的颜色前重构这个引用。

接着,在我们的CopyDude()方法中我们需要克隆鞋子而非拷贝它们:

                public Dude CopyDude()

                {

                    Dude newPerson = new Dude();

                     newPerson.Name = Name;

                     newPerson.LeftShoe = LeftShoe.Clone() as Shoe;

                     newPerson.RightShoe = RightShoe.Clone() as Shoe;

 

                     return newPerson;

                }

现在,当我们执行Main()函数时:

           public static void Main()

           {

                  Dude Bill = new Dude();

                  Bill.Name = "Bill";

                  Bill.LeftShoe = new Shoe();

                  Bill.RightShoe = new Shoe();

                  Bill.LeftShoe.Color = Bill.RightShoe.Color = "Blue";


                  Dude Ted =  Bill.CopyDude();

                  Ted.Name = "Ted";

                  Ted.LeftShoe.Color = Ted.RightShoe.Color = "Red";
 

                  Console.WriteLine(Bill.ToString());

                  Console.WriteLine(Ted.ToString());            

 

           }

我们得到的是:

Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot
Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot

这就是我们想要的。

在通常情况下,我们应该"克隆"引用类型,"拷贝"值类型。(这样,在你调试以上介绍的情况中的问题时,会减少你买来控制头痛的阿司匹林的药量)
在头痛减少的激烈下,我们可以更进一步地使用Dude类来实现IClonealbe,而不是使用CopyDude()方法。

           public class Dude: ICloneable

           {

                public string Name;

                public Shoe RightShoe;

                public Shoe LeftShoe;


                public override string ToString()

                {

                     return (Name + " : Dude!, I have a " + RightShoe.Color  +

                         " shoe on my right foot, and a " +

                          LeftShoe.Color + " on my left foot.");

                    }

                  #region ICloneable Members

                  public object Clone()

                  {

                       Dude newPerson = new Dude();

                       newPerson.Name = Name.Clone() as string;

                       newPerson.LeftShoe = LeftShoe.Clone() as Shoe;

                       newPerson.RightShoe = RightShoe.Clone() as Shoe;
 

                       return newPerson;

                  }

                  #endregion

             }

然后我们将Main()方法中的Dude.CopyDude()方法改为Dude.Clone():

           public static void Main()

           {

                  Dude Bill = new Dude();

                  Bill.Name = "Bill";

                  Bill.LeftShoe = new Shoe();

                  Bill.RightShoe = new Shoe();

                  Bill.LeftShoe.Color = Bill.RightShoe.Color = "Blue";

 
                  Dude Ted =  Bill.Clone() as Dude;

                  Ted.Name = "Ted";

                  Ted.LeftShoe.Color = Ted.RightShoe.Color = "Red";


                  Console.WriteLine(Bill.ToString());

                  Console.WriteLine(Ted.ToString());            
           }

最后的结果是:

Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot.
Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot.

非常好!

比较有意思的是请注意为System.String类分配的操作符("="号),它实际上是将string型对象进行克隆,所以你不必担心会发生引用拷贝。尽管如此你还是得注意一下内存的膨胀。
如果你重新看一下前面的那些图,会发现string型应该是引用类型,所以它应该是一个指针(这个指针指向堆中的另一个对象),但是为了方便起见,我在图中将string型表示为值类型(实际上应该是一个指针),因为通过"="号重新被赋值的string型对象实际上是被自动克隆过后的。

总结一下:

通常,如果我们打算将我们的对象用于拷贝,那么我们的类应该实现IClonealbe借口,这样能够使引用类型仿效值类型的行为。从中可以看到,搞清楚我们所使用的变量的类型是非常重要的,因为在值类型和引用类型的对象在内存中的分配是有区别的。

在下一部分内容中,会看到我们是怎样来减少代码在内存中的"脚印"的,将会谈到期待已久的垃圾回收器(Garbage Collection)。

To be continued...

 

posted @ 2006-05-20 13:35 Andre 阅读(414) | 评论 (4)编辑