Donegal-Irish的垃圾回收站

Moss,WF,WPF,WCF,C#,ADO.NET,ASP.NET,C++,MFC--汇编才是王道

博客园 联系 订阅 管理
  9 Posts :: 0 Stories :: 0 Comments :: 0 Trackbacks

2008年3月17日 #


本文作者:donegal 本文出自: murdercdh.tianya.cn, 转载请注明
最近需要做一个服务器端对OCS的扩展接口,对于微软推出的OCS这套产品,意在整合即时通讯系统。当然就包括一系列的东西,以及一系列的产品的整合,在OCS上面做开发,首先要了解一下他的平台架构,OCS的架构分为中间层平台,服务器平台,用户端平台。利用这三个平台的API的话,理论上可以达到架构在统一沟通平台上的任何功能。当然,现在主要应用比较多的估计还是服务端,客户端,和Web Access端的。

下面列出了所有的目前可以采用的分属不同块API.
 Unified Communications Managed API 1.0
 Unified Communications Client API
 Office Communicator API
 Communicator Web Access API
 Office Communications Server API
 Live Meeting Service API

在客户端开发:个人感觉Ocs2007提供的UCCA比较好用,而且封装比较完善,虽然现在开发的资料比较少,但是仔细研究下SDK也能收获不小了。
在服务端开发:个人感觉Ocs2007提供的UCMA比较不错,同样和客户端的开始包一样,也是托管的代码,在.net平台下做应用和快速开发的首选。




 由于我主要是做的服务端的开发,所以这里主要就是说的UCMA的一些东西,看了几天,和大家分享一些经验,有不对的地方还请大家指出。
下面用这个图来说明一下UCMA的本质,封装在.net库里面的命名空间为Microsoft.Rtc.Signaling,其实个人感觉里面是对服务器的WMI的一些原消息的操作进行了封装,以达到简化开发的效果。所有的托管的API和中间封装层交互,其实真正的WMI的封装还是在图中所显示的Unified Communication Managed Code Middle-Tie Application,如下图.




 对于整个UCMA的开发,首先要了解这个库的基本类结构,如下面的图,几个比较关键的类是管理connection的,管理endpoint的,还有管理session的。
我们先来说管理连接的,连接管理用来管理和维护终端到服务器的连接池,负责维护会话的通道,以及连接的身份验证。UCMA提供两种连接方式,
一种是通过tcp连接,对应的类是RealTimeTcpServerConnectionManager,
一种是通过tls安全连接,对应的类是RealTimeTlsServerConnectionManager,从下面的图可以看出来,这两个类都是集成自抽象类RealTimeServerConnectionManger,至于这两种连接的区别,大家可以参考SDK,这里只是简单的提一下,一种是信任加密的连接,一种就是简单的连接。
这里还有一种方式,采用clientConnectionManager来创建一个连接,但是这样的话就不能对服务器的会话进行监听,只能简单的发送消息。

其次来说是RealTimeEndPoint:
endpoint有两种;
一种是需要连接服务器的单点endPoint,对应的类是SIPENDPOINT
一种是点对点的EndPoint。对应的类是SIPPeerToPeerEndPoint
单点的EndPoint必须要在服务器验证存在,或者是有个服务代理的情况下才能建立的节点。它支持T LAN Manager (NTLM) 和 Kerberos 认证协议,
点对点的EndPoint可以不需要在服务器存在的情况下创建,但是存在一定的局限性,由于不和真实的Server创建连接,那么就无法监听来自服务器的接入和接出的连接,只能限于本身和其他机器之间的通信,期间传送的信息是借助的一个外部绑定的服务代理,具体的实现方法还不知道。大概是规定了一套传输的内容格式,借此来进行识别,本质还是通过tcp协议发了写东西到xx地址去了。由于点对点的传输不需要服务器,那么传输消息的时候就可以在需要传输消息的时候建立一个连接,在消息发送完毕以后就关闭连接。

所共同的地方是他们二者都继承于抽象类RealTimeEndPoint。里面有几个主要的功能函数这里要提一下,异步的发送消息函数,前一个是开始发送,后一个是结束发送,
BeginSendMessage
EndSendMessage
而同时也有同步的方式,采用SendMessage,这里建议单独开一个线程来处理,要不然网络超时的时候系统程序会有比较长的等待
下面是两个比较重要的事件,一个是MessageReceived,一个是SessionReceived,这里意思都很明确,就不多说了。





最后说一下session吧,这里的session绝对不是asp.net里面的session,这里的session实际上是型号量的承载者,里面包含了消息头,消息体,成员等信息。按简单理解来说应该就是一个协议套吧。

说了那么多废话,总结出以下几点:
1. 创建服务端的程序可以根据需要选择ConnectManager的具体类,这样方便用于管理,基本上可以做到,连接提醒,连接消息截获,中断提醒,发送消息等等。
2. 创建的相应的EndPoint可以用来模拟不同的节点,这样就可以应付不同消息量的接收或者发送的需求。
3. 如果建立的是点对点的EndPoint可以不必连接到服务器就可以进行消息的发送,当然如果建立的是ClientConnectManager的话也可以不用配置到服务端的连接了。
4. 所以说,再服务端开发基本就是一下几点:首先创建连接管理类,之后创建相应的endPoint类依附于连接管理类上面,之后根据需要开始程序,截获或者发送session,或者直接封装好的message,或者管理外来到节点的连接,回话。等等。

小弟才疏学浅,看了那么几天大概就看出了那么一点肤浅的明堂,估计有些地方理解还有偏差的,英语水平有限,待以后有时间再加以研究,如果有不对的地方还请大家指出,相互交流。
 具体的层次结构如下图:





文章来源:http://murdercdh.tianyablog.com/blogger/post_show.asp?BlogID=114732&PostID=12854345&idWriter=0&Key=0
posted @ 2008-03-17 22:45 donegal 阅读(122) | 评论 (0)编辑


最近需要在b/s和c/s下面进行对数据库的异步调用,因为有些查询数据库的操作耗时比较大,所以需要,采用异步,或者线程来操作,要不然用户就得等死,为了不让别人等死,所以开始下面的正文。

使用线程来对程序进行操作,但是发现线程需要用好多timer来监听,如果多的话很麻烦,后来发现用异步调用比较好,只要程序结束,结果自动返回。而且实际上也是开了一个后台的线程来进行操作的,感觉有些场合操作起来比线程要实用得多,今天看了下例程,写了点自己的小心得吧。

对于异步调用,用百度搜索,资料绝对是一大堆,但是追其本质,还是在IAsyncResult这个接口的辅助,以及华丽的委托上面。

委托支持同步和异步调用。在同步调用中,一个委托的实例可记录多个目标方法;在异步调用中,一个委托实例中有且只能包含一个目标方法。异步调用使用委托实例的BeginInvoke方法和EndInvoke方法分别开始调用和检索返回值,这两个方法在编译期生成。调用BeginInvoke后委托立即返回;调用EndInvoke时倘若委托方法未执行完毕,则阻塞当前线程至调用完毕。

再来看IAsyncResult这个接口,
// Properties
 object AsyncState { get; }
 WaitHandle AsyncWaitHandle { get; }
 bool CompletedSynchronously { get; }
 bool IsCompleted { get; }
这四个属性用来显示异步调用线程里面的状态,其内部还是开辟了一个线程而回传一个句柄,这个句柄用来监视线程的执行。

要转化同步方法为异步方法,我们这里借助了委托,所以首先要声明一个回调的委托类型;

比如你要调用的方法是这样的,
public string myfunction(int value);
那么你的委托当然应该写成这样
Public delegate string MyFunctionDelegate(int value);

然后开始在需要异步调用的地方开始利用IAsyncResult接口来监听线程的执行。实际上异步调用的关键还是在于委托,大家都知道委托相当于一个函数指针,里面可以订阅相同类型的实际方法,但是委托提供了beginInvoke方法来对所订阅的方法采取异步的方式调用,而且借助IAsyncResult可以获得异步方法调用的句柄,采用endInvoke可以获得异步调用的返回结果。

委托声明完毕,那么下面就开始执行异步调用的具体方式,这里的异步调用大致可以分成5种比较细小的类型,他们的不同之处关键还是在于对异步方法的监听上面,

首先构造委托对象,封装你自己所需要的方法,我这里简单,方法里面就一句话
方法:
public string Myfucntion(int value)
{
 Console.WriteLine("我在等待," + value.ToString());
 return "我做完了!";
}
委托订阅方法:
MyFunctionDelegate mydelegate = new MyFunctionDelegate(Myfucntion);

上面二步做完以后就可以开始异步了:
首先是一直等方式:
这里有2种实现方法,反正都是一直等,
Int value=10;
String result=0;
IAsyncResult aResult = mydelegate.BeginInvoke(value, null, null);
//做你其他想做的,这里面代码肯是是写死的,所以做什么只有在编程时候预定好,界面上、、//面还是锁死的。
result = mydelegate.EndInvoke(aResult);
这样一直等的第一种方式就实现了,
下面是一直等的第二种方式,
不同的地方就是在BeginInvoke和EndInvoke中间放是,
aResult.AsyncWaitHandle.WaitOne();
这里代表的是主线程阻塞,就代表什么都不做,死等,要是方法调用时间很长,比如说10年,那么你准备等老吧,哈哈。

为了不让你等老,下面有两种可以不同等的方法,就是在执行异步调用的时候,可以让你在界面上还做其他的事情。同样还是在中间写
while(aResult.IsCompleted == false)
{
 Thread.Sleep (10) ;
 Application.DoEvents();
}
当然上面的doevent是只有在system.form里面才有的。

最后一种方式是比较高级的方式,就是在异步调用操作结束以后就可以得到返回值,这里需要借助一个委托来获取endInvoke的方法,这个委托是AsyncCallback,写在Begininvoke中,所以异步调用的代码就编程为.
AsyncCallback sss=new AsyncCallback(myAsyncCallback);
IAsyncResult aResult = mydelegate.BeginInvoke(value, sss, null);
回调函数
Public void myAsyncCallback(IAsyncResult ar)
{
 String s;
 MyFunctionDelegate mar=( MyFunctionDelegate)ar.AsyncState;
s = mar.EndInvoke (ar) ;
}

到这里基本的异步调用的集中方式就介绍完毕了。后面的是稍微的一点扩充,就是在asp.net里面采用异步调用的页面,

在asp.net里面,ASP.net2.0提供了十分方便的机制来调用异步页面,

首先要在页面的 @ Page 指令中添加如下的 Async="true" 的属性
究其本质,这段代码的作用是告诉 ASP.NET 在页面中执行 IHttpAsyncHandler。接下来,您需要在页面生存期的早期(例如,在 Page_Load 期间)调用新的 Page.AddOnPreRenderCompleteAsync 方法,以注册一个 Begin 方法和一个 End 方法,如以下代码所示:
AddOnPreRenderCompleteAsync (
 new BeginEventHandler(MyBeginMethod),
 new EndEventHandler (MyEndMethod)
);
Begin 方法还会返回一个 IAsyncResult,它能够让 ASP.NET 确定何时完成异步操作,以便 ASP.NET 能够在这一时刻从线程池提取线程并调用 End 方法。当 End 返回后,ASP.NET 执行包括呈现阶段在内的页面生存期的剩余部分。在 Begin 返回后与 End 被调用前的这段时间内,处理请求的线程处于空闲状态,可以为其他请求提供服务,直到 End 被调用,呈现被显示
protected void Page_Load(object sender, EventArgs e)
 {
 if (!IsPostBack)
 {
 // Hook PreRenderComplete event for data binding
 this.PreRenderComplete +=
 new EventHandler(Page_PreRenderComplete);

 // Register async methods
 AddOnPreRenderCompleteAsync(
 new BeginEventHandler(BeginAsyncOperation),
 new EndEventHandler(EndAsyncOperation)
 );
 }
 }
IAsyncResult BeginAsyncOperation (object sender, EventArgs e,
 AsyncCallback cb, object state)
 {
 string connect = WebConfigurationManager.ConnectionStrings
 ["PubsConnectionString"].ConnectionString;
 _connection = new SqlConnection(connect);
 _connection.Open();
 _command = new SqlCommand(
 "SELECT title_id, title, price FROM titles", _connection);
 return _command.BeginExecuteReader (cb, state);
 }

 void EndAsyncOperation(IAsyncResult ar)
 {
 _reader = _command.EndExecuteReader(ar);
 }
protected void Page_PreRenderComplete(object sender, EventArgs e)
 {
 Output.DataSource = _reader;
 Output.DataBind();
 }

 public override void Dispose()
 {
 if (_connection != null) _connection.Close();
 base.Dispose();
 }


文章来源:http://murdercdh.tianyablog.com/blogger/post_show.asp?BlogID=114732&PostID=12481665&idWriter=0&Key=0
posted @ 2008-03-17 22:45 donegal 阅读(28) | 评论 (0)编辑


本文作者:donegal 转载请注明出处:murdercdh.tianya.cn
有错误的地方请给我E-Mail:murdercdh@126.com

开篇
对于数据挖掘与商业智能这一块内容,Sql Server提供了一整套的解决方案,本着易用,快速的原则,将大部分东西都集成到了SSAS当中,作为中小企业实施BI首选。
 在这里我想重要讲解的是在SSAS当中非常重要的一个环节,MDX语言。
学习新的技术,就好像拿到了一本新的武功图谱,过程总是充满激情,思维的互相碰撞,使整个过程充满悬念,当然可能长时间修炼可能造成枯燥,厌恶,但是为了成为一代大侠,这个过程是原始的积累和学习过程,不可跳跃,除非你是自创武功,独成一派,这样的功力至少需要差不多几十年的积累,张三疯不是一百岁才创太极么?所以各位安身修炼,切不可急躁。

总诀式
首先给出定义:多维表达式 (MDX) 是一种功能完备、基于语句的脚本语言,用于定义、使用以及从 Microsoft SQL Server 2005 Analysis Services (SSAS) 中的多维对象中检索数据。
MDX 提供以下几种语言功能:
1. 用于创建、删除以及使用多维对象的数据定义语言 (DDL) 语句。
2. 用于从多维对象中检索操作数据的数据操作语言 (DML) 语句。
3. 用于管理作用域、上下文以及 MDX 脚本内的流控制的脚本语言语句。
4. 用于操作从多维对象中检索的数据的大量运算符和函数。
要想深入的了解这种语言所带来的巨大优势和遍历,首先需要对整个SSAS的框架体系做一个大致的了解,这样才能更加深入的了解MDX的强大功能以及复杂程度。
Microsoft SQL Server 2005 Analysis Services (SSAS) 使用服务器组件和客户端组件为商业智能应用程序提供联机分析处理 (OLAP) 和数据挖掘功能:

六大心法秘诀:练功者必须仔细体会,待小有所成,亦可不断体会,必有所得。

特性1:Analysis Services 的服务器组件作为 Microsoft Windows 服务来实现。SQL Server 2005 Analysis Services 支持同一台计算机中的多个实例,每个 Analysis Services 实例作为单独的 Windows 服务实例来实现。

特性2:客户端使用公用标准 XML for Analysis (XMLA) 与 Analysis Services 进行通信,XMLA 是一个基于 SOAP 的协议,用于发出命令和接收响应,公开为一项 Web 服务。此外,客户端对象模型通过 XMLA(包括托管提供程序 (ADOMD.Net) 和本机 OLE DB 访问接口)进行提供。

特性3:查询命令可使用下列方式发出:SQL;多维表达式 (MDX)(一种面向分析的行业标准查询语言);或数据挖掘扩展插件 (DMX)(一种面向数据挖掘的行业标准查询语言)。还可以使用 Analysis Services 脚本语言 (ASSL) 来管理 Analysis Services 数据库对象。

特性4:Microsoft SQL Server 2005 Analysis Services (SSAS) 支持瘦客户端体系结构。Analysis Services 计算引擎完全基于服务器,因此,所有查询都在服务器上进行解析。因此,每个查询只需在客户端和服务器之间进行一次来回行程,从而使得性能可以随着查询复杂性的增加而伸缩。

特性5:Analysis Services 的本机协议为 XML for Analysis (XML/A)。Analysis Services 为客户端应用程序提供了数个数据访问接口,但是所有这些组件都使用 XML for Analysis 与 Analysis Services 实例进行通信。

特性6:Analysis Services 提供了数个不同的访问接口,以支持不同的编程语言。访问接口借助 Internet 信息服务 (IIS),并通过 TCP/IP 或 HTTP 发送和接收 SOAP 数据包中的 XML for Analysis 来与 Analysis Services 服务器进行通信。HTTP 连接使用由 IIS 实例化的 COM 对象(称为数据抽取),该对象充当 Analysis Services 数据的管道。数据抽取既不会以任何方式检查包含在 HTTP 流中的基础数据,也不会检查可用于数据库本身中任何代码的任何基础数据结构。

对于ssas有了一个大体的了解以后,就可以开始对具体的mdx语言开始进行学习了。对于一些基础的概念,会穿插到里面进行解释,这样大家就比较容易理解。

下面介绍本门武功的基础概念,这样将有住于练习者领会其中内容,切记,基础乃练功之根本,务必正确领会,否则就像当年梅超疯理解偏差,错炼九鹰白骨爪,终究难成正果。
下面用一个cube例子来解释基础的语言和概念:
关系数据库以二维平面表的形式组织数据。这些表有一个列维度和一个行维度。在每个行和列的交点处只有一个数据元素。
而多维数据库则不同,它是基于称为“多维数据集”的结构,如下图所示。多维数据集按“层次结构”组织数据,而不是以表的形式组织数据。

成员:
成员是维度中的一个项目,表示数据的一次或多次出现。可将维度中的成员看作基础数据库中的一个或多个记录,该记录在此列中的值属于此类别。成员是描述多维数据集中的单元数据时的最低级别的引用。
可以用成员名称或成员键引用某个成员。在上一示例中,用成员在 Time 维度中的名称 4th quarter 来引用该成员。但是,如果维度不具有非唯一的成员名称,则成员名称可以重复,也可以更改渐变维度中的成员名称。
引用成员的另一种方法是引用成员键。维度使用成员键明确标识特定成员。在 MDX 中,“与”符号 (&) 用于区分成员键和成员名称。例如,以下引用使用 4th quarter 成员的成员键 Q4:
[Time].[2nd half].&[Q4]

元组:
包含在多维数据集中的数据元素称为“单元”。通过对多维数据集中包含的每个属性层次结构指定一个成员可以唯一地标识一个单元。标识一个单元的属性的组合称为“元组”。
元组标识多维数据集中的单元。一个元组由多维数据集中每个层次结构中的一个成员组成(显式或隐式引用)。如果特定层次结构中的成员没有在元组中显式引用,则该层次结构中的默认成员将隐式包含在元组中。
在 MDX 中,元组根据其复杂性依照语法进行构造。如果元组只由一个层次结构中的一个成员组成(通常称为“简单元组”),则下列语法是可以接受的:
Time.[2nd half]
例如,下面的元组标识了上图中值为 240 的一个单元(因为这里有四个维度,所以四维定义一个元组):
( Source.[Eastern Hemisphere].Africa,
Time.[2nd half].[4th quarter],
 Route.Air,
 Measures.Packages)

正如可以指定从关系数据库的表中检索多组列或行一样,您可以指定从多维数据集中检索一组元组。MDX 中用来指一个有序的元组集合的标识符称为“集”。下面的示例标识了上图所示的多维数据集中的一个元组集:

{ (Time.[1st half].[1st quarter]),
 Time.[2nd half].[3rd quarter]) }

集:
集是零个、一个或多个元组的有序集合。集最常用于定义 MDX 查询中的查询轴和切片器轴,因此可以只有一个元组,在某些情况下,也可以为空。下面的示例显示了具有两个元组的集:
{ (Time.[1st half], Route.nonground.air), (Time.[2nd half], Route.nonground.sea) }
好了,了解完了这些基本的概念以后就可以正式开始使用mdx语句来获取你想要的数据了,

具体的语句看起来和sql的语句差不多,查询的思路也差不多,但是所有的数据都要以上面的概念去理解,而不是简单的一维度和二维度的,而是多维的,所以要用集合,元组,成员这些概念去理解,一开始接触的人理解起来可能会比较困难,不过慢慢的就可以加深理解了。

下面我们就用几条比较经典的语句来摡略的学习整个mdx的语法,这样的学习方式可能会遗漏许多细节的地方,但是对于快速入门,那是绝对有好处的,在使用熟练度达到一定要求以后,就可以查阅sdk对一些细节的地方进行处理。

内功心法和总诀式这里就介绍完毕了,下面开始具体的招数,每一招分为许多层次,由简单到复杂,切不可急功近利,一定要着重招式的基础部分的领悟,否则很容易走火入魔。

第一式:查询语句
第一层:
SELECT
 { Route.nonground.Members } ON COLUMNS,
 { Time.[1st half].Members } ON ROWS
FROM TestCube

这条语句很简单,就是从Adventure Works里面查询出mesaures维度下的members成员,所查询出来的属性集作为列,而下面的这个Product.Style.CHILDREN属性集作为行。

提示:这里存在三个细节扩展需要注意:
第一个是成员的限定,可以在 MDX 查询中使用 WITH 关键字
第二个是成员的的函数,可用于检索其他 MDX 实体(如维度和级别)中的成员
第三个是查询轴内容和切片器轴内容的查询:
具体的在大家深入以后就会有一个了解。
第二层:
SELECT
 [Measures].[Special Discount] on COLUMNS,
 NON EMPTY [Product].[Product].MEMBERS ON Rows
FROM [Adventure Works]
WHERE [Product].[Category].[Bikes]

这里多加了一个where语句,看似和sql语句差不多,但是理念是不一样的,需要了解下面二个概念:
查询轴:查询轴用于指定由多维表达式 (MDX) SELECT 语句所返回的单元集的范围。通过指定单元集的范围可以限定客户端可以看到的返回数据。
切片器轴:切片器轴将对多维表达式 (MDX) SELECT 语句返回的数据进行筛选,限定返回的数据,从而只返回与指定成员相关的数据。切片器轴是在 MDX 中 SELECT 语句的 WHERE 子句中定义的
每个 MDX 查询都在指定的多维数据集上下文中执行。此上下文定义了由该查询中的表达式求值的成员。
在 SELECT 语句中,FROM 子句用于确定多维数据集上下文。此上下文可以是整个多维数据集,也可以只是该多维数据集的一个子多维数据集。如果通过 FROM 子句指定了多维数据集上下文,就可以使用其他函数来扩展或限制该上下文。

第三层:
WITH SET [ChardonnayChablis] AS
 'Filter([Product].Members, (InStr(1, [Product].CurrentMember.Name, "chardonnay") <> 0) OR (InStr(1, [Product].CurrentMember.Name, "chablis") <> 0))'
SELECT
 [ChardonnayChablis] ON COLUMNS,
 {Measures.[Unit Sales]} ON ROWS
FROM Sales

第四层:
create Session set [Store].[SetCities_2_3] as
{[Data Stores].[ByLocation].[State].&[CA].&[City 02],
[Data Stores].[ByLocation].[State].&[NH].&[City 03]}
这里的第三层和第四层属于同一内容的两个不同方面,应该联系起来学习相互对照,这样可以对这个招术有一个比较深刻的记忆和理解。
查询作用域:若要创建一个命名集,该命名集被定义为 MDX 查询的一部分并且其作用域因此被限制在该查询内,请使用 WITH 关键字。然后,就可以在 MDX SELECT 语句中使用该命名集。通过这种方法,更改用 WITH 关键字创建的命名集时就不会打乱 SELECT 语句。
会话作用域:若要创建一个命名集,使其作用域比查询上下文更广(即,其作用域为 MDX 会话的生存期),请使用 CREATE SET 语句。使用 CREATE SET 语句定义的命名集对该会话中的所有 MDX 查询均可用。例如,CREATE SET 语句对于需要在多种查询中大量重用某个集的客户端应用程序会非常有用。

第五层:
WITH
 MEMBER [Measures].[Special Discount] AS
 [Measures].[Discount Amount] * 1.5
SELECT
 [Measures].[Special Discount] on COLUMNS,
 NON EMPTY [Product].[Product].MEMBERS ON Rows
FROM [Adventure Works]
WHERE [Product].[Category].[Bikes]
这里糅合了前面几层的东西,但是增加了表达式的计算元素,修炼者需要掌握前面级别,方可轻松领悟这一层次。
这里的on colums和on rows的限定,可以用axis函数来代替,他们所表达的意义是相同的,在axis当中,以下数字分别代表不同的维度界定。
0 Columns
1 Rows
2 Pages
3 Chapters
4 Sections
这里需要注意的是如果要采用1,那么必须采用0,如果要采用3,那么必须采用了0,1和2,这里的维度是逐级构造的,不能跳跃。

第六层:
Create Session Member [Store].[Measures].LastFourStores as
sum(([Stores].[ByLocation].Lag(3) :
[Stores].[ByLocation].NextMember), [Measures].[Units Sold])
采用内部成员属性:定义内部成员数次女冠以供使用.
SELECT
 CROSSJOIN([Ship Date].[Calendar].[Calendar Year].Members,
 [Measures].[Sales Amount]) ON COLUMNS,
 NON EMPTY Product.Product.MEMBERS
 DIMENSION PROPERTIES
 Product.Product.[List Price],

 Product.Product.[Dealer Price] ON ROWS
FROM [Adventure Works]
WHERE ([Date].[Month of Year].[January])
这里写了二条语句,第一条的特殊之处在于使用了功能函数对数据成员进行了操作,而后面的一条带cross join的语句记忆后面的DIMENSION PROPERTIES
,涉及到了高级招式的一些细节,在这里不推荐大家练习,待练到后面的招式,这一招自然会融会贯通,切不可操之过急。

小结:
从以上的几个语句,大家可以很好的看到mdx语句以及他的特性,很多细节的东西都在里面了,整个过程是一个由简单到复杂,由主题到细节的过程,具体的还得大家在实际运用中慢慢体会。
Ps:第一式里面的层级就只有六层,一次修炼,不断演练,可达到熟练运用的境界,对于本心法,实战当中用的最多的可能就是第一式里面的东西,所以各位修练者务必做到能构熟练运用。
 
第二式:功能函数
这一层的描述,包含了许多细节的功能函数,这些函数对于在聚合,整合数据的时候起到很大的作用。
第一层:
SELECT Measures.[Internet Sales Amount] ON COLUMNS,
 CrossJoin ( {Product.[Product Line].[Product Line].MEMBERS},
 {[Customer].[Country].MEMBERS}) on ROWS
 FROM [Adventure Works]
这里添加了一个特殊的CrossJoin,其实是对里面的两个成员组的做笛卡尔集,之后再聚合数据。做笛卡尔集的时候有些单元可能是空的,所以有了后面的招数,负责清空空的单元。

第二层:
SELECT Measures.[Internet Sales Amount] ON COLUMNS,
 NonemptyCrossJoin ( {Product.[Product Line].[Product Line].MEMBERS},
 {[Customer].[Country].MEMBERS},Measures.[Internet Sales Amount],2 ) on ROWS
 FROM [Adventure Works]

SELECT Measures.[Internet Sales Amount] ON COLUMNS,
 Nonempty (CrossJoin ( {Product.[Product Line].[Product Line].MEMBERS},
 {[Customer].[Country].MEMBERS}),Measures.[Internet Sales Amount]) on ROWS
 FROM [Adventure Works]
这里有二种方式实现,一种是直接采用原来2000版本的函数NonemptyCrossJoin,还有一种是后来2005新增的函数联用。

第三层:
SELECT Measures.[Internet Sales Amount] ON COLUMNS,
 Filter (CrossJoin ( {Product.[Product Line].[Product Line].MEMBERS},
 {[Customer].[Country].MEMBERS}),[Internet Sales Amount] >2000000) on ROWS
 FROM [Adventure Works]
这里采用了filter函数,对查询出来的数据集进行条件的筛选。后面的
[Internet Sales Amount] >2000000 就是负责限定值在200000以上进行聚合操作。

第四层:
WITH MEMBER Measures.CustomerCount AS DistinctCount (
 Exists ([Customer].[Customer].MEMBERS,[Product].[Product Line].Mountain,
 "Internet Sales"))
 SELECT Measures.CustomerCount ON COLUMNS
 FROM [Adventure Works]
这里同样也是用来筛选数据的,exists用户筛选出数据,后面的Internet Sales,就是筛选的条件。

第三式:作用域限定
第一层:
CALCULATE 语句
使用 Business Intelligence Development Studio 创建多维数据集时,CALCULATE 语句会自动作为第一个语句包含在多维数据集的 MDX 脚本中。CALCULATE 语句通知多维数据集中的每个单元从粒度较小的单元开始聚合。聚合单元后,如果随后使用表达式填充粒度较小的单元,则会影响粒度较大的单元的聚合值。
有效的多维表达式 (MDX) 子多维数据集表达式。
如果用多个赋值计算某个单元,而且赋值相互重叠且可比较(也就是说,两个子多维数据集都具有较高、较低或相同的粒度),则最后传递的赋值在重叠区域具有优先权。例如,运行以下 CALCULATE 语句
Calculate;
({Week.1, Week.2}, Month.Jan) = 20;
({Week.2, Week.3}, Month.Jan) = 40;
运行此 CALCULATE 语句将计算 (Week.All, Month.Jan) 的值,该值等于 20 + 40 + 40 + Week.1 到 Week.3 之外的任何事实数据。

第二层:
This 函数使您可以在 MDX 脚本内检索当前的子多维数据集。您可以使用 This 函数快速将当前子多维数据集内的单元的值设置为 MDX 表达式。在特定计算传递过程中,通常将 This 函数和 SCOPE 语句一起使用,以更改特定子多维数据集的内容。
SCOPE([Customer].&[Redmond].MEMBERS,
[Measures].[Amount], *);
THIS = [Measures].[Amount] * 1.1;
END SCOPE;
SCOPE 语句定义包含 MDX 脚本内其他 MDX 表达式和语句并指定这些表达式和语句的作用域的当前子多维数据集。MDX 在该子多维数据集的上下文内计算其他 MDX 表达式和语句,包括 This 函数和 CALCULATE 语句。
SCOPE 语句本质上是动态的,但不是迭代的。SCOPE 语句中包含的语句运行一次,但子多维数据集本身可以动态确定。例如,有一个名为 SampleCube 的多维数据集。对 SampleCube 多维数据集应用以下 SCOPE 语句以定义一个子多维数据集,将上下文定义为 Measures 维度内的 ALLMEMBERS:
SCOPE([Measures].ALLMEMBERS);
THIS = [Measures].ALLMEMBERS.COUNT;
END SCOPE;

此 SCOPE 语句中包含的语句和表达式运行一次。
现在,商业用户对 SampleCube 多维数据集运行以下 MDX 查询,该查询包含一个名为 ExistingMeasure 的度量值:

WITH MEMBER [Measures].[NewMeasure] AS '1'
SELECT
[Measures].ALLMEMBERS ON COLUMNS,
[Customer].DEFAULTMEMBER ON ROWS
FROM
[SampleCube]

第三层:
在 Adventure Works DW 示例多维数据集的 Finance 度量值组中,以下 MDX 脚本示例使用 SCOPE 语句将 Customer 维度中 Redmond 成员的子级的 Amount 度量值的值设置为比原来增加 10%。但是,另一个 SCOPE 语句将子多维数据集更改为包含 2002 日历年子级的 Amount 度量值。最后,仅为该子多维数据集聚合 Amount 度量值,其他日历年中 Amount 度量值的聚合值则保持不变。

CALCULATE;
SCOPE([Customer].&[Redmond].MEMBERS,[Measures].[Amount], *);
THIS = [Measures].[Amount] * 1.1;
END SCOPE;

第四层:
SELECT Measures.[Internet Sales Amount] on COLUMNS,
 TOPCOUNT ([Product].[Product Categories].[SubCategory].Members,
 10, Measures.[Internet Sales Amount]) ON ROWS
 from [Adventure Works]
 WHERE ([Customer].[Customer Geography].[Country].&[United States])
这里的函数定义了获取聚合值数量,这个函数负责获取聚合出来的前10个值。

第五层:
允许您有条件地从多个比较中返回特定的值。有两种类型的 Case 语句:
简单 Case 语句将某个表达式与一组简单表达式进行比较,以返回特定的值。
搜索 Case 语句计算一组布尔表达式,以返回特定的值。
Case 搜索表达式
若要使用 Case 表达式执行更为复杂的计算,请使用 Case 搜索表达式。使用此搜索表达式的变体可以计算输入表达式是否位于一个值范围内。MDX 按 WHEN 子句出现在 CASE 语句中的顺序计算这些子句。
简单 Case 表达式
MDX 通过将 input_expression 解析为标量值来计算简单 Case 表达式。然后,将该标量值与 when_expression 的标量值进行比较。如果这两个标量值匹配,则 CASE 语句返回 when_expression 的值。如果这两个标量值不匹配,则计算下一个 WHEN 子句。如果所有的 WHEN 子句计算结果均为 False,则返回 ELSE 子句的值(如果存在 ELSE 子句)。

下例中,为每个 WHEN 子句针对指定的 Boolean_expression 计算 Reseller Order Count 度量值。根据每年的 Reseller Order Count 度量值的值返回一个结果。因为按照 WHEN 子句出现的顺序计算这些子句,所以可简单地将所有大于 6 的值赋值为“VERY LARGE”,而无需显式地指定每个值。对于没有在 WHEN 子句内指定的 Reseller Order Count 值,则返回 else_result_expression 的标量值。

WITH MEMBER [Measures].x AS
CASE
WHEN [Measures].[Reseller Order Count] > 6 THEN 'VERY LARGE'
WHEN [Measures].[Reseller Order Count] > 4 THEN 'LARGE'
WHEN [Measures].[Reseller Order Count] > 2 THEN 'MEDIUM'
WHEN [Measures].[Reseller Order Count] > 0 THEN 'SMALL'
ELSE "NONE"
END
SELECT Calendar.[Calendar Year] on 0,
NON EMPTY [Geography].[Postal Code].Members on 1
FROM [Adventure Works]
WHERE [Measures].x

文章来源:http://murdercdh.tianyablog.com/blogger/post_show.asp?BlogID=114732&PostID=12357822&idWriter=0&Key=0
posted @ 2008-03-17 22:45 donegal 阅读(56) | 评论 (0)编辑


记得原来在vc里面写个淡入淡出要一堆代码,今天偶然搜索在C#里面写,发现容易了不少,大致有这么几种实现方式,一种是利用线程,一种是利用timer,无外乎都是改变窗体地Opacity属性而已,很简单,现在把网上剽窃来的代码帖在下面,供自己以后查询使用,哈哈!!!

第一式:构造函数线程刷新式


for(double   d=0.01;   d<   1;   d+=0.02)  
  {  
  System.Threading.Thread.Sleep(1);  
  Application.DoEvents();  
  this.Opacity=d;  
  this.Refresh();  
  }


 第二式:timer计时动态调整式


  private   void   timer1_Tick(object   sender,   System.EventArgs   e)  
  {  
  this.Opacity   =   WinShow   ;  
  WinShow   +=   0.1   ;  
  if(WinShow   >=1   )  
  {  
  timer1.Dispose   ();  
  }  
  }


后面的属于杂变组合招式,心法不变,样子小变。关键是有些小技巧。   
  frmForm   myForm=new   frmForm()  
  frmForm.Opacity=0;  
  frmForm.show();  
  for(int   i=0;i<100;i++)  
  {  
  Application.DoEvents()  
  frmForm.Opacity=i/100;  
  }


  #region     ********   窗体淡入效果函数       ********  
  private   double   WinShow   =   0;//用于窗口淡入效果的变量  
   
  private   void   FormShow(System.Windows.Forms.Form   Curfrm)  
  {  
  Curfrm.Opacity   =   WinShow   ;  
  WinShow   +=   0.01;  
  if(WinShow   ==   1)  
  {  
  Curfrm.timerShow.Stop   ();  
  }  
  }  
   
  #endregion  
   
  #region     ********   窗体淡入效果函数调用示例       ********  
  //实现窗口的淡入效果  
  private   void   timerShow_Tick(object   sender,   System.EventArgs   e)  
  {  
  //timerShow,这是一个timer控件名称;把timerShow.interval=100就可以了。  
  FormShow(this);  
  }  
  #endregion


文章来源:http://murdercdh.tianyablog.com/blogger/post_show.asp?BlogID=114732&PostID=11810506&idWriter=0&Key=0
posted @ 2008-03-17 22:45 donegal 阅读(27) | 评论 (0)编辑


今日闲来无聊,偶然看到一小段代码,拿来实现了一下,后来发现与实际的内容发生了一点点出入,于是浅浅的写下一小点很简单的问题,希望对大家有帮助,
采用2.0的.net发送邮件可以利用现成的MailMessage这个类来构造需要发送的邮件信息,这个类,感觉就是封装了简单的邮件信息,当然,格式完全是按照邮件的协议来安排的。老版本的是调用SmtpMail发送的,其用来和服务器验证的密码账号都是以field添加到里面去的,2.0采用了比较安全的方式,SmtpClient来发送,默认的验证采用的是信用认证模式,具体的大家看代码就可以了解,当然还可以采用异步方式发送,可以封装一个事件,当邮件成功发送或者成功接收,就调用自己方法。下面贴代码,没技术含量,完全就是用来说明一下。如果有什么问题就参考msdn,很好搞定。

老版本1。0的做法:
public void sendmail10()
 {
 Try
{
 MailMessage mailMessage = new MailMessage();
 mailMessage.To = "xxxxxx@163.com";//收件人名
 mailMessage.From = "xxxxxx@163.com";//发件人
 mailMessage.Subject = "标题";
 mailMessage.Body = "xxxxxx";//邮件内容
 mailMessage.BodyFormat = MailFormat.Html;
 mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1" ); //认证类型
 mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", "xxxxxx@163.com" );//要认证的用户名
 mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", "xxxxxx" ); //要认证的密码
 string smtpServer = "smtp.163.com";//163邮箱
 SmtpMail.SmtpServer= smtpServer;
 SmtpMail.Send( mailMessage );
 }
 catch( Exception E )
 {
 Response.Write( E.Message );
 return;
 }

}

2.0版本的做法。
――――――――――――――
public void sendmail20()
 {
 try
 {
 MailMessage mailMessage = new MailMessage();
 mailMessage.To = txtTo.Text;//收件人名
 mailMessage.From = txtFrom;//发件人
 mailMessage.Subject = txtTitle.Text;//标题
 mailMessage.Body = txtContext.Text;//邮件内容
 mailMessage.IsBodyHtml = true;

 string smtpServer = "smtp.163.com";//163邮箱
 SmtpClient smtpMail = new SmtpClient(smtpServer);
 smtpMail.UseDefaultCredentials = false;
 smtpMail.Credentials = new System.Net.NetworkCredential("账号", "密码");
 smtpMail.Send(mailMessage);
 }
 catch (Exception E)
 {
 Response.Write(E.Message);
 return;
 }
 }
----------------
网络上有人整合了下,写成一个包了,小封装了下,感觉写的不错,避免了大家的重复劳动,这里直接帖出来,反正也是自己看,哈哈。这里需要注意下的是,邮件账号必须是有smtp服务权限,有些免费邮箱的账号貌似权限不够,就是说连接smtp服务器会出问题,作者的代码把连接的账号信息添加到config配置文件里面了,数据都是从里面读的。
具体配置节是在


config文件中
<system.net>
<mailSettings>

<smtp from="admin@your-domain.com">
<network host="your-mail-server-name"
userName="your-user-name"
password="your-password" />
</smtp>
</mailSettings>
</system.net>

其实这里最好还是做成表,放excel表里面,这样就可以支持好多了。当然,密码如果用明文是不安全的,最好采用加密方式储存,要是简单点,自己写个加密小算法也可以,呵呵。就说这么多,没技术含量,外加剽窃,嘿嘿!!!

作者是yyw‘s.
-------------------------------
using System;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Threading;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Net.Configuration;
using System.Configuration;

namespace Mailer.Components
{
邮件发送类#region 邮件发送类

public class SMTP
{
Fields#region Fields

private string _mailFrom;
private string _displayName;
private SmtpClient smtpMail;

#endregion

Properties#region Properties

public string MailFrom
{
get { return _mailFrom; }
set { _mailFrom = value; }
}

public string DisplayName
{
get { return _displayName; }
set { _displayName = value; }
}

#endregion

Constructors#region Constructors

public SMTP()
{
System.Configuration.Configuration config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~/");
MailSettingsSectionGroup mailSettings = (MailSettingsSectionGroup)config.GetSectionGroup("system.net/mailSettings");

string mailFrom = mailSettings.Smtp.From;
string smtpServer = mailSettings.Smtp.Network.Host;
int smtpPort = mailSettings.Smtp.Network.Port;
string smtpUsername = mailSettings.Smtp.Network.UserName;
string password = mailSettings.Smtp.Network.Password;

smtpMail = new SmtpClient(smtpServer, smtpPort);
smtpMail.Credentials = new NetworkCredential(smtpUsername, password);
this._mailFrom = mailFrom;
this._displayName = smtpUsername;
}

public SMTP(string smtpServer, string userName, string password)
: this(null, smtpServer, userName, password)
{
}

/**////
/// 邮件发送类
///

/// 发件人地址
/// SMTP 服务器
/// 用户名
/// 密码
public SMTP(string mailFrom, string smtpServer, string userName, string password)
: this(mailFrom, mailFrom, smtpServer, userName, password)
{

}

/**////
/// 邮件发送类
///

/// 发件人地址
/// 显示的名称
/// SMTP 服务器
/// 用户名
/// 密码
public SMTP(string mailFrom, string displayName, string smtpServer, string userName, string password)
: this(mailFrom, displayName, smtpServer, 25, userName, password, false)
{
}

public SMTP(string mailFrom, string displayName, string smtpServer, int smtpPort, string userName, string password, bool smtpSsl)
{
this._mailFrom = mailFrom;
this._displayName = displayName;
smtpMail = new SmtpClient(smtpServer, smtpPort);
smtpMail.Credentials = new NetworkCredential(userName, password);
smtpMail.EnableSsl = smtpSsl;
}


#endregion

Methods#region Methods

Public#region Public

public Boolean Send(string mailTo, string mailSubject, string mailBody, MailPriority priority, bool isBodyHtml)
{
string[] mailTos = new string[] { mailTo };
string[] attachments = null;
System.Text.Encoding bodyEncoding = System.Text.Encoding.Default;
return Send(mailTos, null, null, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
}

public Boolean Send(string mailTo, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
{
string[] mailTos = new string[] { mailTo };
return Send(mailTos, null, null, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
}

public Boolean Send(string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
{
return Send(this._mailFrom, this._displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
}

/**////
/// 同步发送邮件
///

///
public Boolean Send(string mailFrom, string displayName, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
{
return SendMail(false, null, mailFrom, displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
}

public void SendAsync(object userState, string mailTo, string mailSubject, string mailBody, MailPriority priority, bool isBodyHtml)
{
string[] mailTos = new string[] { mailTo };
string[] attachments = null;
System.Text.Encoding bodyEncoding = System.Text.Encoding.Default;
SendAsync(userState, mailTos, null, null, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
}

public void SendAsync(object userState, string mailTo, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
{
string[] mailTos = new string[] { mailTo };
SendAsync(userState, this._mailFrom, this._displayName, mailTos, null, null, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
}

public void SendAsync(object userState, string mailFrom, string displayName, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
{
SendMail(true, userState, mailFrom, displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
}

/**////
/// 异步发送邮件
///

/// 异步任务的唯一标识符
///
public void SendAsync(object userState, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
{
SendMail(true, userState, null, null, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);
}


/**////
/// 发送邮件
///

/// 是否异步发送邮件
/// 异步任务的唯一标识符,当 isAsync 为 True 时必须设置该属性, 当 isAsync 为 False 时可设置为 null
///
private Boolean SendMail(bool isAsync, object userState, string mailFrom, string displayName, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
{
bool mailSent = false;

设置属性值#region 设置属性值

if (string.IsNullOrEmpty(mailFrom))
mailFrom = this._mailFrom;

if (string.IsNullOrEmpty(displayName))
displayName = this._displayName;

MailMessage Email = GetMailMessage(mailFrom, displayName, mailTos, mailCcs, mailBccs, mailSubject, mailBody, attachments, priority, isBodyHtml, bodyEncoding);

smtpMail.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);

#endregion

try
{
if (!isAsync)
{
smtpMail.Send(Email);
mailSent = true;
}
else
{
userState = (userState == null) ? Guid.NewGuid() : userState;
smtpMail.SendAsync(Email, userState);
}
}
catch (SmtpFailedRecipientsException ex)
{
//System.Windows.Forms.MessageBox.Show(ex.Message);
mailSent = false;
}
catch (Exception ex)
{
//System.Windows.Forms.MessageBox.Show(ex.Message);
mailSent = false;
}

return mailSent;
}

#endregion

Private#region Private

private MailMessage GetMailMessage(string mailFrom, string displayName, string[] mailTos, string[] mailCcs, string[] mailBccs, string mailSubject, string mailBody, string[] attachments, MailPriority priority, bool isBodyHtml, System.Text.Encoding bodyEncoding)
{
// build the email message
MailMessage emailMessage = new MailMessage();

if (string.IsNullOrEmpty(mailFrom))
mailFrom = this._mailFrom;

if (string.IsNullOrEmpty(displayName))
displayName = this._displayName;

MailAddress mailFromObject = new MailAddress(mailFrom, displayName);

emailMessage.From = mailFromObject;

if (mailTos != null)
{
foreach (string mailto in mailTos)
{
if (!string.IsNullOrEmpty(mailto))
{
emailMessage.To.Add(mailto);
}
}
}

if (mailCcs != null)
{
foreach (string cc in mailCcs)
{
if (!string.IsNullOrEmpty(cc))
{
emailMessage.CC.Add(cc);
}
}
}

if (mailBccs != null)
{
foreach (string bcc in mailBccs)
{
if (!string.IsNullOrEmpty(bcc))
{
emailMessage.Bcc.Add(bcc);
}
}
}

if (attachments != null)
{
foreach (string file in attachments)
{
if (!string.IsNullOrEmpty(file))
{
Attachment att = new Attachment(file);
emailMessage.Attachments.Add(att);
}
}
}

emailMessage.Subject = mailSubject;
emailMessage.Body = mailBody;
emailMessage.Priority = priority;
emailMessage.IsBodyHtml = isBodyHtml;
emailMessage.BodyEncoding = bodyEncoding;

return emailMessage;
}

private void SendCompletedCallback(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
bool mailSent = false;

// Get the unique identifier for this asynchronous operation.
String token = e.UserState.ToString();

if (e.Cancelled)
{
//Console.WriteLine("[{0}] Send canceled.", token);
mailSent = false;
}
if (e.Error != null)
{
//Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
mailSent = false;
}
else
{
//Console.WriteLine("Message sent.");
mailSent = false;
}

mailSent = true;
}

#endregion

#endregion
}

#endregion
}

文章来源:http://murdercdh.tianyablog.com/blogger/post_show.asp?BlogID=114732&PostID=11808924&idWriter=0&Key=0
posted @ 2008-03-17 22:45 donegal 阅读(26) | 评论 (0)编辑


声明:这里并不是在讨论传统老师教授的++a,和a++的先后问题。


C#版本


------------------


using System;


using System.Collections.Generic;
using System.Text;



namespace ConsoleTest


{


    class Program


    {


        static void Main(string[] args)


        {


            Int a=10;


a = a++;


Console.WriteLine(a.ToString());


}


}



}


C++版本


---------------------------------------------


#include "stdafx.h"

#include

using namespace std;



int _tmain(int argc, _TCHAR* argv[])
{


      int a=10;


a=a++;


cout<<a;


}


        有一天下班,同事兴致冲冲的跑过来,二话不说,在我的的键盘上风风火火敲下了3行代码,并且在编译执行以前神秘的问了我一句,输出是多少?
    诈一看代码,不觉的有些吃惊,很简单的一行,可能大多数人都不会这样写,但是就有人如此写下了,随之就是脑袋的高速运转。假设数据输入的是10,那么输出是多少呢?按常理来说,肯定是有悖常理的,同事才会如此着迷,于是回答输出还是10


    编译运行,果然是10,难道编译器错了?于是换用vc编译器编译执行,输出是11。看来javac#都错了。只有C++对了,百思才有头绪,于是开始探究编译的过程,把原来的编译原理的知识都用上了,反汇编代码,饶有兴趣的开始逐一比较分析,共享些许小心得。



a=a++;c++版本)


004113D5  mov         eax,dword ptr [a] 
004113D8  mov         dword ptr [a],eax


004113DB  mov         ecx,dword ptr [a]

004113DE  add         ecx,1
004113E1  mov         dword ptr [a],ecx


a = a++;C#版本)


00000040  mov         edi,dword ptr [ebp-44h] 


00000043  lea         eax,[edi+1]


00000046  mov         dword ptr [ebp-44h],eax 


00000049  mov         dword ptr [ebp-44h],edi


    不难看出,在C++的编译器里面,编译出来的汇编代码的确是按照用户的意图执行的,首先是解析表达式,然后对表达式进行运算,这里首先做的是把a的值给eax,然后把eax里面的内容复制到a的地址里面,这里进行的操作自然就是aa;复制的时候当然是用过ax寄存器。运算完毕以后,再对a自身做加1的操作,这里是通过cx寄存器来操作的,完全符合表达式的意图。


但是我们再一看C#的反汇编代码,问题就来了,这里首先把a的地址给了di寄存器,因为对于c#里面的值类型,数值是分配在stack上面的,所以这里减了一个偏移的地址【44h】,之后将di里面的东西加了1,然后把地址给了ax存了起来,之后再把ax里面的内容给了变量a放值的地方,其实做的是赋值,在这个时候,编译器里面a的那个地址的值的确是11,但后最后还来了1句,把di里面的东西还原给了a。十分诧异,为什么这个式子在c#的编译器里面出来的是这种结果呢。显然编译器没有按照我们的意图对式子进行解析。稍微分析一下,发现,在C#里面,做自加的时候,编译器首先是把当前需要自加的变量存到了di寄存器里面,先在ax寄存器里面做自加,之后在表达式运算结束以后,再将原来寄存器di里的值拿过来赋值,刚好遇上了是赋值给本身,所以前面的值就被冲了。于是解析出来这个值就变成了10。哈哈,这里应该是编译器处理的问题,对于X++操作,首先找个寄存器存放他的值,然后在本地址的值做自加计算,最后还原给值,这种找个地方存起来处理表达式的办法果然不好,c++的编译器做的就很明智,等你运算表达式结束,我再来对你操作。


         呵呵,粗略的分析了一下汇编的代码得到的信息就那么多了,其实整个式子的解析过程没有那么简单,里面首先要进行表达式解析,里面设计到运算符优先级判断,以及堆栈的进出问题,具体的还是要看编译器是怎么来处理的,呵呵,看不到编译器的代码,没辙。


         另外,在java的编译器里面输出的结果也和c#的是一样哦!!!


文章来源:http://murdercdh.tianyablog.com/blogger/post_show.asp?BlogID=114732&PostID=11667593&idWriter=0&Key=0
posted @ 2008-03-17 22:45 donegal 阅读(6) | 评论 (0)编辑




对于moss2007里面的BDC这一块的内容,是新加进来的特性。这块功能十分类似于java里面的ORM,当然实现上面肯定是有质的区别。Bdc提供了一种数据共享的业务,为连接后台和表层业务数据建立了桥梁。实际上bdc为上层应用提供服务,实例化以后其实就是数据实体,简单的说就是Entity,我们不用担心bdc如何提供的这些实体,因为很多东西都已经在LobSystem里面处理了。只需要调用就可以,并且这些实体可以运用到各种Web Parts里面,成为共享的数据之一。




对于实体的描述,在BDC里面实际上是通过xml语言来进行的。




每一个实体,里面可以包含诸多东西,具体的大家可以看sdk里面的那张实体描述的图。在entity节里面大家可以发现method,identifier,property等节,他们都描述了实体是一个什么样的,即实体的方法,类型等。这里我只能粗略的说下我的一些经验,对于每一个方法群,实体必须要有一个方法的实例:即MethodInstance,只有这样实体才能调用方法的实例来获取数据。同样在方法里面可以定义你自己的数据筛选器,描述节为FilterDescription。利用BDC可以采用两种方式来获取数据,一种是采用web Service,一种是采用传统的ADO。在LobSystem里面提供两种配置,一个是采用WebServiceProxyNamespace,一个是采用RdbConnection。分别对应web Serviceado。这里不得不说一下,在moss里面的web service是托管的,所以在moss里面部署的Web Service必须采用特殊的格式。即:wsdl,disco文件必须做相应的更改。详细的一些步骤这里就不再说明,sdk里面有详细的部署方法。




每一个entity来说,必须有相应的方法名,数据名称,变量的描述,自定义类型的描述必须引入相应的类型。所有的parameter 的描述都是通过TypeDescriptor节来描述的,并且这些描述节可以嵌套。这样无论多复杂的parameter都可以被嵌套按层次描述出来。对于描述出来的方法,必须有相应的methodInstance,一个method可以有多个instance,但不能没有。




先说RdbConnection这种方式,也就是采用LobSystem里面自带的ADO引擎,首先我们必须定义采用引擎的数据提供类型,数据库类型,数据库名字等一系列的属性的定义,这些定义是在LobSystemInstance节里面描述的,其实这样做起来十分像java里面配置Hibernate里面的ORM后台数据库的配置节,其实这一套体系还是和java十分类似,由于看不到源代码,但是采用的设计模式应该差不多,同样也有连接池来维护一定数量的连接。对于数据的读取,这一块采用的主要是这两个接口,一个是IDataReader,IDataRecord,对于Entity的存放,采用的接口是IEntityInstanceEnumeator,IEntityInstance。前面二个接口是用来和数据库交互的,后面两个接口是用来和Entity交互的。对于后面两个接口,明眼人一下就可以看出来,一个是多条记录的枚举器,一个是单条记录。Sdk上面有几个画的很漂亮的图,因为我这里图片不好上传,传了还容易失效,所以就不贴图了(偷懒!!)。




再来说web service,BDC里面可以直接调用web service来创建自己的实体方法,我们所需要做的,只是在实体描述文件里面描述相应的web Service方法就可以了。这样我们就可以导入自己的实体,并且实体的数据是从网络上获得的。SDK有一个亚马逊的调用Web Service的例子,我没有做通,因为登陆采用的是pass through方式,那个代理服务器的地址一直没找到(如果有知道的,希望告知,万分感激!!!)。个人只是自己写一个调本地数据库web Service,然后自己写了一个entity的描述文件导入到了里面。这里有二个值得注意的地方,一个是对于Web Servicemoss里面的部署,一个是添加到web parts里面显示,对于数据库权限的控制。第一个问题只要细心的一般都可以搞定,部署在_layouts里面的Web Service通过moss托管,配置文件需要做相应的更改,实际上就是把soap里面的搜索地址更改了一下,具体的是这样改的:




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




这个描叙需要改为:




<%@ Page Language="C#" Inherits="System.Web.UI.Page" %>




<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>




<%@ Import Namespace="Microsoft.SharePoint.Utilities" %>




<%@ Import Namespace="Microsoft.SharePoint" %>




<% Response.ContentType = "text/xml"; %>




实际上就是把原来的纯xml变换成为一个page来解析。并且这个页面的解析是通过moss处理的,




<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request) + "?wsdl"),Response.Output); %>

<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> 



对于contractRef 还有soap address这两个节的更改,需要改成上面的方式,实际上是在页面里面重新编码了soap的查询url,这样做的目的也是为了moss托管的web service可以正确定位。具体里面详细的机制我还不是摸得很清楚,因为本身对soap协议没有什么深刻的学习,希望还有达人指教。




 




如果你的BDC实体描述文件里面WebServiceProxyNamespace是写的自己虚机的地址,也就是说你调用的web service方法是部署在自己的虚机上面的,那么你就可以不需要上面的步骤就可以正常导入运行。但是这样做有一个非常麻烦的地方,运行的时候必须开虚机,要不然web Service是无法调用到的。对于数据库的权限问题,必须在数据库里面添加相应用户的权限,我用的是sql2005,这里应该在sql里面添加我当前域的可以访问moss用户的,对数据库读取的权限。具体的大家参看sql2005的配置,如何添加相应角色。对于部署在虚机上面的web service,也需要在数据库里面添加用户,NT AUTHORITY/NETWORK SERVICE,这样moss才能调用web service方法来访问数据库。Moss的权限这块做的很复杂,结合了ad,rmi这些东西偶都涉猎不深,还有待学习。




以上只是自己一些凌乱的心得和经历,很多东西都没有理解的很透彻,就像一个刚入门的孩子,站在wss的门口,看着这座大楼复杂的构架,众多新鲜的事务。很多东西都还需要学习。在这里希望和大家一起交流,一同进步。


文章来源:http://murdercdh.tianyablog.com/blogger/post_show.asp?BlogID=114732&PostID=11483519&idWriter=0&Key=0
posted @ 2008-03-17 22:45 donegal 阅读(27) | 评论 (0)编辑



 ASP.NET ISAPI 扩展启动辅助进程后,它将传递部分命令行参数。辅助进程使用这些参数来执行加载 CLR前需要执行的任务。传递的值包括:COM 和 DCOM 安全性所要求的身份验证等级、可以使用的命名管道的数量和 IIS 进程标识。命名管道的名称是使用IIS 进程标识和允许