澳门新葡亰网址下载在C#中使用COM+实现事务控制

by admin on 2020年2月2日

1) 在建立C#工程之后必须要给类一个强名称。
要创建强名称,可以使用 sn
工具。此命令行工具有许多选项,在命令提示符处键入 sn /?
可以查看所有选项。对程序集签名所需的选项是“-k”,它将创建一个密钥文件。默认情况下,该文件使用
.snk 作为扩展名。例如,要创建一个名为 MyCom.snk
的密钥文件,可以使用以下命令行:
 sn -k MyCom.snk
然后在工程中引用这个强名称
方法如下:
(1):注释掉AssemblyInfo.cs中的[assembly:
AssemblyKeyFile(“”)]和[assembly: AssemblyKeyName(“”)]
(2): 在组件类中写入
using System.Data.OleDb;//引用ADO.net命名空间
using System.Data;//引用数据空间
using System.Runtime.InteropServices;//为了调用GUID
                       
System.EnterpriseServices命名空间包涵所有COM+的类型库所以在编写COM+组件的时候一定要用到System.EnterpriseServices命名空间,这个命名空间在引用中.net页下可以找到
      using System.EnterpriseServices;//引用COM+名命空间
            using System.Runtime.CompilerServices;//运行时编译服务器
      using System.Reflection;//用些全局属性取得强名属性
[assembly: ApplicationName(“myCom”)]
                 //强名文件名和文件属性。用sn.exe生成,用法 sn -k
mycom.snk
      [assembly: AssemblyKeyFileAttribute(“mycom.snk”)]
[assembly: AssemblyKeyName(“mycom.snk”)]
   (3)组件类的写法
组件类的写法有二种一种是以前的那种
一种是基于接口编程的例如
namespace myCom//把所有代码写到相应的命名空间内
{
//每一个接口一个GUID号
[Guid(“549047DE-9F3B-4781-A1F6-F3C852091FC9”)]
//接口类型ComInterfaceType.InterfaceIsDual接示接口需要双重公开给COM+
//这个属性是接口的属性
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
//定义接口
public interface Add

关于在vs 2005 C#中如何使用COM+,这是前几天作项目遇到的,一开始真是一头雾水,上网查了好多资料也是好多说法,经过一翻努力终于搞定,呵呵,现在把使用过程记录下来,希望能与大家一起分享!

  .NET技术是微软大力推广的下一代平台技术,自从.NET技术架构的正式发布,此项技术也逐渐走向成熟和稳定。按照微软的平台系统占有率,我们不难想象得到,在未来的一两年内.NET技术必定会势如破竹一般的登上主流的技术平台,而一个新的技术平台得以快速发展的最重要的前提是:他不会彻底的摒弃以前的技术,这一点对于.NET技术来说指的就是COM/COM+技术了。

{
接口内的方法返回布尔值有一个整型参数
bool AddData(int d);

COM+需要服务器端(部署服务或组件)和客户端(使用服务),我觉得COM+更合适于B/S系统中,当然在我做的银行管理系统中C/S和B/S都有了!下面就开始吧…..

  一般来说,在IT技术界以及硬件产业,技术的更新换代速度非常得惊人,而惯例是所有的新技术都会遵循向下兼容的原则,但是.NET技术不仅仅做到了这一点,.NET甚至实现了相互之间的各自调用,这一点是非常难能可贵的。也就是说,不但我们可以在.NET组件中调用COM组件,同时也可以在COM组件中正常的调用.NET组件。这点带来的好处是显而易见的,一方面我们可以保持现有的技术资源,另一方面,在现有资源中可以利用.NET所带来的各种新技术。

bool AddDataM(int d);
}
       //实现这个接口
//事务属性表示需要新事务
//这个属性用来记录类是否支持事务有车个选项同VB中类的属性相同
 [Transaction(TransactionOption.RequiresNew )]
//在类中实现这个接口必须要继承System.EnterpriseServices;命名空间的ServicedComponent类
//在后面继承前面所定义的接口如果有多个可以用“,”分开
 public class myClass:ServicedComponent,Add
 {
//  public myCom.myClass   error =new ErrorsLibrary.Class1();

(一)   在解决方案中:选[文件]->[添加]->[新建项目]->[类库] 
(我是使用一个类库改造成Com+),把它命名为Bank,它包含两个文件{Bank.cs(把Class1.cs重命名成Bank.cs得到的)和AssemblyInfo.cs}

  一般的数据库事务控制要求事务里所做的操作必须在同一个数据库内,这样在出现错误的时候才能回滚(RllBack)到初始状态。这就存在一个问题,在分布式应用程序中,我们往往需要同时操作多个数据库,使用数据库本身的事务处理,很难满足程序对事务控制的要求。在COM+中,提供了完整的事务服务,我们可以利用它来完成在分布式应用程序中的事务控制。

  //定认字符变量用来存放数据库连接字符串
  private static string strConnect
=”Provider=MSDAORA.1;Password=erpii;User ID=erpii;Data
Source=erpii;Persist Security Info=True”;
  //创建这个连接
  private OleDbConnection conConnection = new OleDbConnection (
strConnect ) ;
   
   

(二)   在Bank类库中添加引用,[右击]->[添加引用]->.NET组件中->System.EnterpriseServices

  具体过程如下

  //实现接口中的查询方法
  public bool AddData(int id)
  {
   try
   {

(三)   回到Bank.cs中在代码上添加using System.EnterpriseServices;
然后定义银行操作的接口,BankOperation

  一:用VS.NET生成一个类库 。

    //string StrSql=”insert into    TEST1   values( ‘” + id + “‘)”;
    string StrSql=” insert into    test_d  values( ‘” + id + “‘,”
     +”‘” + id + “‘,”
     + “‘” + id + “‘,”
     + “‘” + id + “‘)”;
    //     string StrSql=”DELETE FROM TEST1″;
    //找开连接
    conConnection.Open(); // 打开数据连接
    //执行查询
    OleDbCommand cmd = new OleDbCommand ( StrSql , conConnection ) ;
    cmd.ExecuteNonQuery ();
    conConnection.Close ();

         //BankOperation 接口的定义

  二:添加对System.EnterpristServices的引用,具体步骤

    //ContextUtil.SetComplete() ;
    return true;
   }
   catch (Exception e)
&

      public interface BankOperation

  菜单:(项目-添加引用-在.NET选项卡选择System.EnterpristServices-确定)

 {

  三:构建类

         ….

  1:源程序

        
//利用卡号取款

using System;
using System.EnterpriseServices;
using System.Data.SqlClient;
using System.Reflection;

        bool
WithdrawByCardNo(string CardNo, decimal amount);

namespace COMPlusSamples
{
//表明需要事务支持
[ Transaction(TransactionOption.Required) ]
//声明为服务器应用程序,还可以选择Library,表示为库应用程序
[澳门新葡亰网址下载,assembly: ApplicationActivation(ActivationOption.Server)]
//描述信息
[assembly: Description(“sample”)]

 }

public class TxCfgClass : ServicedComponent
{
private static string init1 = “user id=sa;password=;initial
catalog=pubs;data source=(local)”;

(四)   改造Bank.cs中的Bank类,让它继承BankOperation接口和ServicedComponent, 它会自动有个提示,按Tab键,便会生成接口中抽象类的实现

private static string init2 = “user id=sa;password=;initial
catalog=NorthWind;data source=(local)”;

         public class Bank : ServicedComponent, BankOperation

private static string add1 = “insert into
authors(‘au_lname’,’au_fname’) values(‘test1’, ‘test2’)”;

{

private static string add2 = “insert into sample values(‘test1’,22)”;
//the error sql statement
//there is not table “sample”

      …

public TxCfgClass() {}

      bool WithdrawByCardNo(string CardNo, decimal amount)

private void ExecSQL(string init, string sql)
{
SqlConnection conn = new SqlConnection(init);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = sql;
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}

      {

//添加一条记录到数据库
public void Add()
{
try
{
//在一数据库中插入一条记录

         
Throw(…异常…);

ExecSQL(init1, add1);
Console.WriteLine(“the operation in the same database completely”);

         
//此处就是操作的具体实现了,当然要自己写代码

//在另外一个数据库中插入两条记录
//这次执行的是一个错误的SQL语句

         }

ExecSQL(init2, add2);
Console.WriteLine(“the operation in the other database
completely”);

}

Console.WriteLine(“Record(s) added, press enter…”);
Console.Read();

(五)   可以Bank.cs中也可以在AssemblyInfo.cs中添加设置一些使用时的配置(如设置服务器启动模式,组件安全性,认证方式,代理等等..相关的资料上网找找吧…)代码如下

}
catch(Exception e)
{
//事务回滚
ContextUtil.SetAbort();
Console.WriteLine(“Because there are some errors in the operation ,so
transcation abort”);
Console.WriteLine(“The error is ” + e.Message);
Console.WriteLine(“abort successfully”);
Console.Read();
}
}
}
}
2:程序说明:

命名空间外:

  添加命名空间 using
System.EnterpriseServices;因为本程序使用了其中的ContextUtil类
[ Transaction(TransactionOption.Required) ] 说明DLL需要事务支持。

using System;

  本程序的TxCfgClass
类从ServicedComponent类中继承,这样并不会影响该类,而只是在该类中添加了两个额外的方法,这两个方法可以使代码共享变得更加容易。

using System.Collections.Generic;

  程序使用的sql server数据库在本机运行,init1 和
init2是两个连接数据库的连接字符串,init连接pubs数据库,inin2连接northwind数据库,这是sql2000中自带的示例数据库。add1和add2是两条sql语句,作用是分别向两个数据库的表里添加一条记录。注意:add2是一条错误的语句,因为根本没有sample表,这样,会在执行时引起异常。(这正是我们所期望的)

using System.Text;

  在执行到add2语句时,由于它是错误的,所以会引发异常,转到错误处理语句里来执行。

using System.Data.SqlClient;

  ContextUtil.SetAbort();该语句使所有的数据库操作回滚,这样add1语句所插入的记录也将不存在。(达到预期目标)

using System.Collections;

  四:给程序添加强名(strong name)

using System.EnterpriseServices;

  1:创建一对密钥

//配置Bank组件的安全性,并且说明组件的激活方式是服务器激活

  用来创建密钥的工具是称为sn.exe的共享工具。通常通过命令提示运行它,该工具可执行各种任务以生成并提取密钥。我们需要用以下方式来运行sn.exe。

[assembly: ApplicationAccessControl(

sn –k key.snk

       
AccessChecksLevel = AccessChecksLevelOption.ApplicationComponent,//进程安全级别,组件级别

  其中key.snk
代表将保存密钥的文件的名称。它的名称可以是任意的,不过习惯上带有.snk后缀名。

       
Authentication = AuthenticationOption.Call,//认证为调用每个方法时都要认证

  2:签名

       
ImpersonationLevel = ImpersonationLevelOption.Delegate)]//安全性的扮演角色是代理

  签名通常是在编译时进行的。签名时,用户可利用C#属性通知编译器应该使用正确的密钥文件对DLL进行签名。要做到这一点用户需要打开工程中的AssemblyInfo.cs文件并进行修改。

//激活方式:服务器激活

  [assembly:AssemblyKeyFile(“..\..\key.snk”)]

[assembly: ApplicationActivation(ActivationOption.Server)]

  注:key.snk文件和项目文件在同一个文件夹

 

  五:编译成DLL (具体步骤)

namespace Bank

  菜单:(生成-生成)

{

  如果一切正常,就会生成DLL文件

  六:使用regsvcs.exe将Dll注册到COM+ Services里面

}

  我们需要用以下方式运行regsvcs.exe

命名空间中:

  regsvcs dll文件名

     //设置支持事务

  如果一切正常的话,regsvcs.exe就会把dll输入到COM+ Services中。

    [Transaction(TransactionOption.Supported)]

  至此,我们已经生成并注册了这个可以由其它程序使用的类,现在,我们来写一个控制台程序来检验这个类是否正常运行

    //使用对象池,最小共享量是10,最大共享容量是50,创建时限是30秒,单位从毫秒记

  七:构建客户机

    [ObjectPooling(true, 10, 50, CreationTimeout =
30000)]

  1:新建控制台应用程序项目

    //使用用时激活(JITA)

  菜单(文件-新建-项目)

    [JustInTimeActivation(true)]

  选择控制台应用程序 ,并选择 添入解决方案 ,确定

    //定义构造字符串

  2:同上面的第二步一样,添加对System.EnterpriseServices的引用。

    [ConstructionEnabled(Default = “server=.;database=Bank;uid=sa;pwd=sa;”)]

  3:添加对自己刚才做好的类的引用。

    //定义安全角色

  菜单(项目-添加引用-浏览),选择刚才生成的DLL,确定

[SecurityRole(“bank”, true)]

  4:输入以下程序

[ComponentAccessControl]

using System;
using COMPlusSamples;
using System.EnterpriseServices;

 

public class Client
{
public static void Main()
{
TxCfgClass cfg = new TxCfgClass();
cfg.Add();
}
}

关于构造字符串的使用:

  5:将控制台程序设置为启动项,然后编译运行,就会看到结果。

     在类Bank中重置Construct()方法

  正如我们希望的,第一条记录没有插入数据库

         string connString;

        protected override void Construct(string s)

        {

            base.Construct(s);

           
connString = s;

    }

(六)   以上就是实现一个COM服务,要想使用它那还几步要操作,那就是生成它的一个强名称

(相当于注册了),步骤如下:

1.打开vs 2005命令提示符:系统的[开始]->[所有程序]->[Microsoft visual studio
2005]->[Visual studio Tools]->[Visual studio 2005 命令提示]

2.输入cd 路径(你这个类库所在的文件绝对路径)比如我的文件在E:C#电子银行Bank  E:C#电子银行Bank >然后输入 sn –k Bank.snk;生成密匙Bank.snk为生成的文件名称,( 执行完成后,文件里会多出一个文件Bank.snk )

(七)   强名称生成完后,回到程序AssemblyInfo.cs中最后几排,可以发现(也可能没有自己写)[assembly: AssemblyKeyFile(”
“)]

把文件路径写进去[assembly:
AssemblyKeyFile(“..\..\server.snk”)]

(八)   在解决方案—…>电子银行BankobjDebug,在obj debug 中会有个Bank.dll回到Visual Studio .Net2005 命令提示,到文件objdebug目录下(cd objdebug),执行regsvcs 命令,注册服务。我机器上是这样的E:C#电子银行Bankobjdebug > regsvcs
Bank.dll;(或regsvcs *.dll)  这样,服务器就构建完成。

(九)   打开我的电脑,控制面板 ,管理工具,组件服务,com+应用程序 ,现在我们可以看到com+中多了个,Bank这个就是你所建的服务器

(十)   在server上按右键,打开属性,修改安全性:调用身份验证级别为:无,模拟级别为标识。授权下的勾去掉( 这些是根据情况需要更改的,现在仅仅做个本机上的列子 )。然后找到激活,远程服务器名称 改成你自己机器的IP地址。

(十一)           
建立客户端。建一个winfrom(窗体)如ATM,加入引用:using
System.EnterpriseServices

 using Bank;在客户端要引用的地方new(创建Bank的对象如private Bank.Bank
bank;因           为Bank为类库,引其中的Bank类) 一下就可以直接用其中的方法了。

 

 

以上便是创建和使用com+的过程,大家相互学习有什么问题一起讨论….

附部分代码:

<Bank类库>

using System;

using System.Collections.Generic;

using System.Text;

using System.Data.SqlClient;

using System.Collections;

using System.EnterpriseServices;

 

 

//配置Bank组件的安全性,并且说明组件的激活方式是服务器激活

[assembly: ApplicationAccessControl(

       
AccessChecksLevel = AccessChecksLevelOption.ApplicationComponent,//进程安全级别,组件级别

       
Authentication = AuthenticationOption.Call,//认证为调用每个方法时都要认证

       
ImpersonationLevel = ImpersonationLevelOption.Delegate)]//安全性的扮演角色是代理

//激活方式:服务器激活

[assembly: ApplicationActivation(ActivationOption.Server)]

 

namespace Bank

{

   

    //定义所有的操作

    //BankOperation 接口的定义

    public interface BankOperation

    {

        ….

        //利用卡号取款

        bool WithdrawByCardNo(string CardNo, decimal amount);

    }

 

    //设置支持事务

    [Transaction(TransactionOption.Supported)]

    //使用对象池,最小共享量是10,最大共享容量是50,创建时限是30秒,单位从毫秒记

    [ObjectPooling(true, 10, 50, CreationTimeout =
30000)]

    //使用用时激活(JITA)

    [JustInTimeActivation(true)]

    //定义构造字符串

    [ConstructionEnabled(Default = “server=.;database=Bank;uid=sa;pwd=sa;”)]

    //定义安全角色

    [SecurityRole(“bank”, true)]

    [ComponentAccessControl]

 

    public class
Bank : ServicedComponent, BankOperation

    {

        private string connString;

        public Bank()

        {

 

        }

        //重置Construct()方法

        protected override void Construct(string s)

        {

            base.Construct(s);

           
connString = s;

        }

 

        //GetConnection()方法用配置好的连接字符串从数据库获取数据库链接

        private SqlConnection GetConncetion()

        {

            SqlConnection conn = new SqlConnection();

           
conn.ConnectionString = connString;

            return conn;

        }

         #region BankOperation 成员

        public bool
WithdrawByCardNo(string CardNo, decimal amount)

        {       
…………

            string AccountNo;

            bool result;

           
AccountNo = QueryAccountNo(CardNo);

            if (AccountNo == “error”)

            {

               
result = false;

            }

            else

            {

               
result = WithdrawByAccountNo(AccountNo, amount);

            }

            return result;

        }

       
#endregion    }}

 

<ATM窗体>

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Bank;

 

namespace 电子银行

{

    public partial class ATM :
Form

    {

       …

        private Bank.Bank bank;

 

        public ATM()

        {

           ..

            bank =
new Bank.Bank();

        }

    }

}

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图