.NET技术在中国为什么老被人嫌弃

该日志由 samool 发表于 2019-11-10 11:38:00

今天看到一篇文章,写的挺中肯的,转发

这个话题有点自黑的意思,我从.NET 1.1开始玩.NET,到现在已经11年了,我是看着.NET成长起来,在中国壮大的,也见证了近几年.NET被各种嫌弃,其实说到底还是中国的架构师太少,我是说真正懂行的架构师,一个资深的架构师是不会直接攻击一门语言或者嫌弃一门语言的,而是会从操作系统、服务器应用容器层面是分析性能、实现成本以及有多少坑。

我其实和很多客户、IT经理、高级软件工程师、架构师聊过,所以对事实有一定的了解。首先呢在中国技术圈氛围就是很浮躁的,浮躁到什么程度,还是中国人的老毛病,喜欢跟风、喜欢一窝蜂,人家用node.js,我们就用node.js;人家用docker,我们也用docker;人家用CloudFoundry,我们也用CloudFoundry,总之人家的东西比我们家先进,所以我们一定要跟上。拿docker来说,其实很多传统企业根本没有用,也就是几家互联网大厂对它情有独钟;Node.js我承认它性能好,但毕竟是弱语言编程,其实代码的维护成本并不低,而且你需要雇佣很资深的Javascript开发人员,薪水自然是水涨船高。其实很多所谓的架构师、IT经理考虑的不是迁移成本、运维成本,而是怎么找点事做,这样才能体现出自己的价值,我总结为四个字“无中生有”。

.NET中的C#语言(我的最爱)其实从1.0发展到6.0,目前已经非常成熟了,特别是语言层面的异步编程支持,已经部分超越了Java,那为什么还是没有公司愿意选它呢?从我的角度看,有几方面的原因。

首先微软的IDE实在是太好用了,好用到基本上找个应届生,就算不懂编程,1-2天内也能写个控制台程序,当然是简单的;但如果是Eclipse,配环境也要好一会儿,但这意味着什么知道吗?门槛!人的门槛!越好用的东西聚集的人相对越Low,当然并不是说用.NET的人烂,而是说平均而言,真正懂.NET的开发人员相对于懂Java的开发人员要少,因为人家的IDE用起来各种不舒服,还不如用Notepad++和Java.exe做编译。这就导致了Java的工程师很多时候必须知其然知其所以然,否则它没法干活,比如jar打包。但很多.NET的程序员估计连怎么用命令行编译程序都不会,这就是问题。

其次一些号称懂.NET的架构师觉得.NET简单,所以他们不愿意给.NET开发高工资,这也间接导致了很多.NET开发人员开始转向其他语言,其实这种模式就是个恶性循环。到最后的结果就是,大量潜在的优秀开发人员放弃.NET,毕竟现在是向钱看的年代。.NET从我的角度看是非常适合做后端,这么多年技术的积淀使得.NET得到了社区广泛认可,其实在国外懂.NET还是很吃香的,根本不愁找不到工作,所以国内一些公司的逻辑我觉得很奇怪,甚至觉得神奇,反正我就是不招.NET工程师,我公司比较高大上,所以只有高达上的Java、Node.js 才能配得上我司,我只能说,不作不死。

再者,.NET可以抄的现成架构并不多,而真正懂.NET的资深架构师在中国基本属于稀有物种,因为这些公司的所谓架构师水平有限,他们自己用.NET写不出好的架构代码(我通常喜欢叫他们集成师,即不会写代码或者写不好代码的架构师),最终还是选Java,因为Java有一大堆架构可以抄,而且很多是开源的,就算不会也至少能抄个4-5成吧。当然咯,从项目风险可控角度这是可以接受的,但其实资深架构师是可以解决这些问题的,在国外很多架构牛人基本都是自己写框架的,这也就能解释为什么优秀且流行的框架基本上都是洋人写的,比如Java的Structs、Spring framework, .NET的Orchard、DNN、ASP.NET Biolerplate等。

最后,微软作为.NET亲爹自然难辞其咎,自从纳总上台后,更是拼命推行拥抱开源政策,拥抱了一堆非.NET系语言,尽管推出了跨平台.NET即.NET Core,但在.NET市场布局和推广方面与过去并没有什么明显不同,说白了就是表现对.NET份额出无所谓的态度。不过微软一直是行业中比较傲娇的公司,它觉得只要自己想推什么肯定能成功,所以对市场份额从来表现的不太看重,他觉得根本不需要在意,迟早是微软的。然并卵,微软手机的失败让微软感受到了自己能力的有限,最近貌似在调整策略,其实回过头来看代价非常高,单收购诺基亚就花了85亿,我只能赞叹微软真土豪,有钱任性,呵呵。

我必须承认近2年.NET的中国市场份额在不断下降,很大程度上与.NET的市场推广策略有关,给行业内一种中低端编程语言的假象,在语言推广初期,这种策略没有什么错误,便于用户上手和接受,但是如今都10年了,重新树立.NET高大上技术的形象非常必要。

有人可能要说我属于老王卖瓜自卖自夸了,我举几个真实的.NET案例你就懂了,沪牌拍牌系统后台是.NET写的,并发至少几千每秒,这个大家懂的;Stackoverflow核心是.NET写的,网站并发 3000每秒,数据库并发 8000每秒;摩根斯坦利交易客户端以及协议是.NET写的;NASDAQ的交易系统是.NET写的,后台跑的SQL Server;腾讯有大量后台系统用.NET写,腾讯甚至已经使用跨平台.NET(Mono)很多年,部署于它的TLinux系统集群中;携程有大量系统用.NET写成,日均动态PV是3千万。

文章来源:https://blog.csdn.net/prospertu/article/details/86543656

该日志标签: .net

c#的DateTime.Now函数详解

该日志由 samool 发表于 2013-12-31 10:11:00

//2008年4月24日

 System.DateTime.Now.ToString("D");
 //2008-4-24
 System.DateTime.Now.ToString("d");
 //2008年4月24日 16:30:15
 System.DateTime.Now.ToString("F");
 //2008年4月24日 16:30
 System.DateTime.Now.ToString("f");
 //2008-4-24 16:30:15
 System.DateTime.Now.ToString("G");
 //2008-4-24 16:30
 System.DateTime.Now.ToString("g");
 //16:30:15
 System.DateTime.Now.ToString("T");
 //16:30
 System.DateTime.Now.ToString("t");
 //2008年4月24日 8:30:15
 System.DateTime.Now.ToString("U");
 //2008-04-24 16:30:15Z
 System.DateTime.Now.ToString("u");
 //4月24日
 System.DateTime.Now.ToString("m");
 System.DateTime.Now.ToString("M");
 //Tue, 24 Apr 2008 16:30:15 GMT
 System.DateTime.Now.ToString("r");
 System.DateTime.Now.ToString("R");
 //2008年4月
 System.DateTime.Now.ToString("y");
 System.DateTime.Now.ToString("Y");
 //2008-04-24T15:52:19.1562500+08:00
 System.DateTime.Now.ToString("o");
 System.DateTime.Now.ToString("O");
 //2008-04-24T16:30:15
 System.DateTime.Now.ToString("s");
 //2008-04-24 15:52:19
 System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ffff");
 //2008年04月24 15时56分48秒
 System.DateTime.Now.ToString("yyyy年MM月dd HH时mm分ss秒");
 //星期二, 四月 24 2008
 System.DateTime.Now.ToString("dddd, MMMM dd yyyy");
 //二, 四月 24 ’08
 System.DateTime.Now.ToString("ddd, MMM d \"’\"yy");
 //星期二, 四月 24
 System.DateTime.Now.ToString("dddd, MMMM dd");
 //4-08
 System.DateTime.Now.ToString("M/yy");
 //24-04-08
 System.DateTime.Now.ToString("dd-MM-yy");
//字符型转换转为字符串
12345.ToString("n");  //生成 12,345.00
12345.ToString("C"); //生成 ¥12,345.00
12345.ToString("e"); //生成 1.234500e+004
12345.ToString("f4"); //生成 12345.0000
12345.ToString("x"); //生成 3039 (16进制)
12345.ToString("p"); //生成 1,234,500
 //本年度销售额、本季度利润、本月新增客户 

 //今天

 DateTime.Now.Date.ToShortDateString();
 //昨天,就是今天的日期减一
 DateTime.Now.AddDays(-1).ToShortDateString();
 //明天,同理,加一
 DateTime.Now.AddDays(1).ToShortDateString();
 //本周(要知道本周的第一天就得先知道今天是星期几,从而得知本周的第一天就是几天前的那一天,要注意的是这里的每一周是从周日始至周六止
 DateTime.Now.AddDays(Convert.ToDouble((0 - Convert.ToInt16(DateTime.Now.DayOfWeek)))).ToShortDateString();
 DateTime.Now.AddDays(Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek)))).ToShortDateString();
 //如果你还不明白,再看一下中文显示星期几的方法就应该懂了
 //由于DayOfWeek返回的是数字的星期几,我们要把它转换成汉字方便我们阅读,有些人可能会用switch来一个一个地对照,其实不用那么麻烦的             
 string[] Day = new string[]{ "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
 Day[Convert.ToInt16(DateTime.Now.DayOfWeek)];
 //上周,同理,一个周是7天,上周就是本周再减去7天,下周也是一样
 DateTime.Now.AddDays(Convert.ToDouble((0 - Convert.ToInt16(DateTime.Now.DayOfWeek))) - 7).ToShortDateString();
 DateTime.Now.AddDays(Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek))) - 7).ToShortDateString();
 //下周
 DateTime.Now.AddDays(Convert.ToDouble((0 - Convert.ToInt16(DateTime.Now.DayOfWeek))) + 7).ToShortDateString();
 DateTime.Now.AddDays(Convert.ToDouble((6 - Convert.ToInt16(DateTime.Now.DayOfWeek))) + 7).ToShortDateString();
 //本月,很多人都会说本月的第一天嘛肯定是1号,最后一天就是下个月一号再减一天。当然这是对的
 //一般的写法
 DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + "1"; //第一天
 DateTime.Parse(DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + "1").AddMonths(1).AddDays(-1).ToShortDateString();//最后一天
 //巧用C#里ToString的字符格式化更简便
 DateTime.Now.ToString("yyyy-MM-01");
 DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddMonths(1).AddDays(-1).ToShortDateString();
 //上个月,减去一个月份
 DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddMonths(-1).ToShortDateString();
 DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();
 //下个月,加去一个月份
 DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddMonths(1).ToShortDateString();
 DateTime.Parse(DateTime.Now.ToString("yyyy-MM-01")).AddMonths(2).AddDays(-1).ToShortDateString();
 //7天后
 DateTime.Now.Date.ToShortDateString();
 DateTime.Now.AddDays(7).ToShortDateString();
 //7天前
 DateTime.Now.AddDays(-7).ToShortDateString();
 DateTime.Now.Date.ToShortDateString();
 //本年度,用ToString的字符格式化我们也很容易地算出本年度的第一天和最后一天
 DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).ToShortDateString();
 DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddYears(1).AddDays(-1).ToShortDateString();
 //上年度,不用再解释了吧
 DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddYears(-1).ToShortDateString();
 DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddDays(-1).ToShortDateString();
 //下年度
 DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddYears(1).ToShortDateString();
 DateTime.Parse(DateTime.Now.ToString("yyyy-01-01")).AddYears(2).AddDays(-1).ToShortDateString();
 //本季度,很多人都会觉得这里难点,需要写个长长的过程来判断。其实不用的,我们都知道一年四个季度,一个季度三个月
 //首先我们先把日期推到本季度第一个月,然后这个月的第一天就是本季度的第一天了
 DateTime.Now.AddMonths(0 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01");
 //同理,本季度的最后一天就是下季度的第一天减一
 DateTime.Parse(DateTime.Now.AddMonths(22 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();
 //下季度,相信你们都知道了。。。。收工
 DateTime.Now.AddMonths(22 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01");
 DateTime.Parse(DateTime.Now.AddMonths(6 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();
 //上季度
 DateTime.Now.AddMonths(-22 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01");
 DateTime.Parse(DateTime.Now.AddMonths(0 - ((DateTime.Now.Month - 1) % 22)).ToString("yyyy-MM-01")).AddDays(-1).ToShortDateString();

该日志标签: .net, 日期

.NET Framework 3.5 sp1离线安装方案

该日志由 samool 发表于 2011-05-31 11:41:56

.net Framework 3.5 Service pack 1(Full Package) 231MB是网络上最完整的离线安装包,安装时却还提示要联网下载,如果没联网就麻烦了,这里下载的是语言包。这里教你自己动手制作真正的.net Framework 3.5 Service pack 1完整离线安装包.

第一种解决.NET Framework 3.5 sp1离线安装方案
1、下载.net Framework 3.5 Service pack 1 (Full Package) 231MB 安装包后dotnetfx35.exe,用WinRAR打开并解压。
2、下载.net Framework 3.5 Service pack 1中文简体语言包
一般用户下载dotnetfx35langpack_x86zh-CHS.exe,这个是WIN32系统
3、将语言包dotnetfx35langpack_x86zh-CHS.exe复制到第一步解压缩的\wcu\dotNetFramework\dotNetFX35\x86文件夹里。(如果是x64位的,可将dotnetfx35langpack_x64zh- CHS.exe 复制到\wcu\dotNetFramework\dotNetFX35\x64文件夹里。)
4、点击运行dotNetFx35setup.exe,可彻底的离线安装了。

第二种解决.NET Framework 3.5 sp1离线安装方案
在没有装VS2008的机器上单独安装3.5SP1的时候,无论你下载的什么完整版还是非完整版,安装程序都需要连接Internet,去下一些东东,而且超慢。更要命的是:提示有63M的东西要下,然后已经下了63M了,还是在下。
先说解决方案:
1.到官网上下载3.5SP1的完整安装包。
2.下载完成后,命令行下运行dotnetfx35.exe /x解压到一个目录
3.进入解压目录下进入wcu\dotNetFrameWork
4.从命令行运行dotNetFx35setup.exe /lang:ENU
5.OK一路畅通了。

该日志标签: .net, sp1, Framework

c#检查字符串是否为数字

该日志由 samool 发表于 2007-12-28 10:01:21

正则表达
   string regex = @^\d+$;

  自己写个方法吧:这是我写的.
          private bool isNumber(string s)
   {
    int Flag = 0;
    char[]str = s.ToCharArray();
    for(int i = 0;i < str.Length ;i++)
    {
     if (Char.IsNumber(str[i]))
    {
     Flag++;
    }
   else
   {
    Flag = -1;
    break;
   }
  }
  if ( Flag > 0 )
  {
   return true;
  }
  else
  {
   return false;
  }
          }

测试
                   private void Button1_Click(object sender, System.EventArgs e)
  {
   if (isNumber(TextBox1.Text.Trim()))
   {
    TextBox2.Text = 是数字;
   }
   else
   {
    TextBox2.Text = 不是数字;
   }
  }

 

try
{
 double.Parse(this.TextBox1.Text);
 Response.Write(是数字);
}
catch
{
 Response.Write(不是数字);
}

或者用正则表达式也可以:
using System.Text.RegularExpressions;
------------------------
Regex r=new Regex(@^\d+(\.)?\d*$);
if(r.IsMatch(this.TextBox1.Text))
{
 this.Response.Write(是数字);
}
else
{
 this.Response.Write(不是数字);
}

public static bool StrIsInt(string Str)
    {
      try
      {
        Int32.Parse(Str);
        return true;
      }
      catch
      {
        bool flag = false;
        return flag;
      }
    }

 

应该使用正则表达式:
string pattern = @^\d+(\.\d)?$;
if(Text1.Text.Trim()!=)
{
if(!Regex.IsMatch(sign_money.Text.Trim(),pattern))
{
   Text1不是数字;
}
else
{
  Text1是数字;
}
}

该日志标签: .net, 字符串, 数字

VB6如何访问.NET WebService服务

该日志由 samool 发表于 2007-10-18 16:53:37

首先安装Microsoft SoapToolkit,因为VB自身不支持WebService,需要安装SoapTookit后能调用WebService。

下载SoapTookit3.0

然后在VB6中点菜单“工程”—“引用”-把“Microsoft Soap Type Libray v3.0” 打上钩就可以了。

     Dim mysoap As New SoapClient30
     mysoap.MSSoapInit ("https://samool.com/soap/Webservice.asmx?WSDL")
     Label1.Caption = mysoap.helloWorld(Text1.Text)

按上面方法直接调用WebService函数就OK了。

该日志标签: webservice, .net, vb6, soaptoolkit, soapclient

Working with .NET data in Delphi

该日志由 samool 发表于 2007-06-24 12:29:04

Webservices offer a rich world of functionality. This world is available to the Delphi programmer with the introduction of the Webservice importer introduced in Delphi 6, with version 6.02 also available in Delphi pro. A webservice can work with pretty complex data, with .NET it is a snap to return and  receive complete XML datasets. Delphi does not know how to work with these datasets natively. In this paper I will show how to work with .NET data using the GekkoDotNetDataset componenet.

The .NET webservice

The webservice I am going to build will be a web-wrapper round a database. The database is an Access database local on the web-server. It  contains  customers, invoices and invoice details.

Methods of the webservice will expose this data to the web as strongly typed XML datasets. Other methods will accept XML datasets to update the database. Importing these tables in a .NET application will result in a nice XSD schema

For a step by step story how to build such a service you can read one of my dotnetjunkies stories, for the moment I will concentrate on the actual webmethods.

The Customers method returns a dataset containing all customers. It does so by creating a new typed dataset object : DataSetCustomers. This object is filled by the oleDbDataAdapter, the internals of this component do the real access to the database.

 

 

public DataSetCustomers Customers()
{
    DataSetCustomers ds =
new DataSetCustomers();
    oleDbDataAdapterCustomers.Fill(ds);
   
return ds;
}

The entire resulting XML dataset is returned. One of the many nice things of an XML dataset is that it can be serialized, it can be represented as one long string of characters. Which is something which is very easy to transport over the standard HTTP protocol.

To fill the contents of the invoices dataset, as described by the schema, takes a little more effort. The three tables can live together in one dataset but for every table another oleDbDataAdapter is needed.

[WebMethod]

public DataSetInvoices Invoices()
{
    DataSetInvoices ds =
new DataSetInvoices();
    oleDbDataAdapterCustomers.Fill(ds.Customers);
    oleDbDataAdapterInvoices.Fill(ds.Invoices);
    oleDbDataAdapterInvoiceDetails.Fill(ds.InvoiceDetails);
   
return ds;
}

Using dataAdapters all query possibilities of the database can be used. For an example you are still invited at the dotnetjunkies. DataAdapters can also be used to write to a database. The updates to be written are passed as a typed XML dataset. Which make the implementation of of the webmethod a one-liner:

[WebMethod]

public void UpDateCustomers(DataSetCustomers ds)
{
    oleDbDataAdapterCustomers.Update(ds.Customers);
}

Multiple tables can be updated in one go in the UpdateInvoices method. The order in these updates will be performed is important:

[WebMethod]

public void UpdateInvoices(DataSetInvoices ds)
{
    oleDbDataAdapterCustomers.Update(ds.Customers);
    oleDbDataAdapterInvoices.Update(ds.Invoices);
    oleDbDataAdapterInvoiceDetails.Update(ds.InvoiceDetails);
}

You cannot enter a new invoice if you don't know the customer yet. These integrity checks are also performed in an .NET XML dataset object. But in there they can be switched off by setting the EnforceConstraints property to false.

A .NET webservice consumer at work

In .NET you can build a windows client application which imports the webservice and it will work perfect with all functionality of the webservice. Which means that a windows application can update an Access database somewhere on a webserver on the other side of the globe using plain HTTP.

The client reads that data from the webserver like this

localhost.DataSetWebService ws =

new localhost.DataSetWebService();
dataSetCustomers1.Clear();
dataSetCustomers1.Merge(ws.Customers());

The dataset is bound to a grid. Here the user can do some editing after which the update is invoked

localhost.DataSetWebService ws =

new localhost.DataSetWebService();
ws.UpDateCustomers(dataSetCustomers1);

See this consumer at work in the dotnetjunkies story.

Importing the webservice in Delphi

It would be very nice to work with this webservice in Delphi. I will use Delphi 6.02 pro which has full support for webservices clients. Delphi has a webservice importer which is found under the file | New | Other | Webservices menu. After entering the URL of the webservice Delphi will generate a unit describing the webservice.

The webservice has two types, being the Customers and the Invoices XSD schema. The service has four methods who use these types in their parameters or as result-type. And this is what the Delphi makes out of it :

Which looks pretty disappointing. The Return types of Customers and Invoices webmethods are recognized as composite types Customers and Invoices. Alas, these types contain no members at all. Things get worse with the update methods. Both have a parameter named ds of type Invoices or Customers. The importer generates two methods with a parameter named ds of a type named ds as well. This ds type is declared and does not have any members either. That's not going to work. Many webservices work very well with Delphi but in this case it will need some extra help.

Introducing the GekkoDotNetDataSet component 

I have built the GekkoDotNetDataSet component. This component is based on the HTTPrio component and can be found in the demo code. It takes the following approach to the problem:

  • It wraps up one XML dataset.
  • It provides the data to other Delphi components as (client-)datasets.
  • The webservice has to have a function member which returns the typed dataset.
  • The webservice has to have an update member which accepts the typed XML dataset in a parameter.

The component introduces two new published events and one new published property, visible in the object inspector.

  • OnRequestGetInvocation, an event which is fired when the component requests the XMLdataset from the service.
  • Paramname. A string to store the name of the parameter of the updatemethod.
  • OnRequestUpdateInvocation, an event which is fired when the component requests the webservice to update the data.

The component has two public methods and two public properties to read and write data

  • The Get method reads the data into the componennt.
  • The DataTable publishes all data in an array of Delphi (Client)datasets.
  • TableCount counts the number of Delphi datasets.
  • The Update method sends all updates to the webservice

This componenet is part of the GekkoDotNetPackage, it will install itself on the webservices page.

Reading data with GekkoDotNetDataSet component 

I drop two of these components on the form. One for the Web Services' Customers dataset and the other for the Invoices dataset. Despite it's emptiness I can use the imported Service1.pas. The GekkoDotNetDataSet component is a HTTPrio descendent so I have to set the WSDLlocation in both components , it will be http://localhost/WebServices/DataService/Service1.asmx?wsdl. The component's only new property is ParamName, it is the name of the parameter of the Update methode, ds for both components.

The real new stuff is in two new events. These get fired when the component Get's or Update's data. As the component does not know which member of the webservice to invoke to read or write data it will make a callback to the component's user. Requesting the user to do the actual invoke.

procedure TForm1.DataSetCustomersRequestGetInvocation(Sender: TObject);
var Iservice : DataSetWEbServiceSoap;
   begin
   Iservice:= DataSetCustomers as DataSetWebServiceSoap;
   Iservice.Customers;
   end;

You have to get to the actual webservice by typecasting the component to the interface of the service, which can be done because the component is a HTTPrio wrapping up the webservice. The declaration of DataSetWebServiceSoapis in the imported Service1.pas. On this interface you call the function which will return the intended XML dataset. In the requestGetInvocation-eventhandler of the other componenent the Invoices method will be invoked.

The click of a button will fill the form with a dataset, which dataset depends on a radiogroup

procedure TForm1.ButtonGetClick(Sender: TObject);
var i : integer;
    DNdataSet : TGekkoDotNetDataSet;

   begin
   case RadioGroup1.ItemIndex of
        0 : DNdataSet:= DataSetCustomers;
        1 : DNdataSet:= DataSetInvoices;
        else DNdataSet:= nil;
        end;
   if Assigned(DNdataSet) then
      begin
      DNdataSet.Get;
      CreateDataGrids(DNdataSet);
      end;
   end;

By calling get on the customers dataset the DataSetCustomersRequestGetInvocation eventhandler will be executed. Which will make the right invocation.

Now the tables of the are filled I will show what's in them. The form has an empty pagecontrol. For every dataset a page is added to the pagecontrol : 

procedure TForm1.CreateDataGrids(Sender: TObject);
   var tP : tTabSheet;
   ds : tDataSource;
   dn : tDBNavigator;
   dg : tDBGrid;
   i : integer;

   DNdataSet : TGekkoDotNetDataSet;

   begin

   DNdataSet:= sender as TGekkoDotNetDataSet;
   if DNdataSet <> nil then
      begin
      for i:= 0 to DNdataSet.TableCount - 1 do
          begin
          tP:=tTabSheet.Create(self);
          tP.PageControl:= PageControl1;
          tP.Caption:= DNdataSet.DataTable[i].Name;

          ds:= tDataSource.Create(Self);

          dn:= tDBnavigator.Create(self);
          dn.Align:= alTop;
          dn.Parent:= tP;
          dn.DataSource:= ds;

          dg:= tDBGrid.Create(self);
          dg.Align:= alClient;
          dg.Parent:= tP;
          dg.DataSource:= ds;

          ds.DataSet:= DNdataSet.DataTable[i];
          end;
      end;

   end;

For every (client-)dataset in the GekkoDotNetDataSet I create a new page with a datagrid and a dbNavigator.

When running this application I can browse and update the data in my Delphi form.

Updating data with GekkoDotNetDataSet component 

To return all updates to the webservice the component uses another event

procedure TForm1.DataSetInvoicesRequestUpdateInvocation(Sender: TObject);
var Iservice : DataSetWEbServiceSoap;
   begin
   Iservice:= DataSetInvoices as DataSetWebServiceSoap;
   Iservice.UpDateInvoices(ds.Create);
   end;

This event is fired by the componenet when it's Updatemethodis called. The component does not know which member to invoke, in this eventhandler the component' user is requested to invoke the desired method. Theds class is declared in the imported unit. It has no members but it will do to invoke the method.

The form sends the updates by the click of a button

procedure TForm1.ButtonSaveClick(Sender: TObject);
var DNdataSet : TGekkoDotNetDataSet;
   begin
   case RadioGroup1.ItemIndex of
      0 : DNdataSet:= DataSetCustomers;
      1 : DNdataSet:= DataSetInvoices;
      else DNdataSet:= nil;
      end;
   if Assigned(DnDataSet) then
      DNdataSet.Update;
   end;

Now we have a Delphi application which works with a .NET webservice and can read or write XML dataset data.

Inpecting the webservice's request and response

To get an idea what is going on I have set the GekkoDotNetDataSet componenet's before- and after- execution event to show the full SOAP request and response in explorer windows.

The request is passed to the eventhandler as a string and the response as a stream. The ShowXMLmethod will send the stream to a browser, it does so by saving the xml as a temporary file and pointing a browser to it. In the BeforeExcute event the string request has to be written to a stream before being sent to the ShowXML method.

procedure TForm1.HTTPRIO1BeforeExecute(const MethodName: String; var SOAPRequest: WideString);
   var ts : tStringStream;
   buffer : string;
begin
   buffer:= SOAPrequest;
   ts:= tStringStream.Create(buffer);
   Showxml(ts, Send);
end;

procedure TForm1.HTTPRIO1AfterExecute(const MethodName: String; SOAPResponse: TStream);
begin
   ShowXML(SOAPResponse, Receive);
end;

Now you can see the full requests as they are sent to the .NET webservice and the response.

(Don't) try this ay home !

The GekkoDotNetDataSet component relies on the tDNdataSet, whose internals are described in another paper. The class has been created by trial and error in investigating the results of .NET built webservices. If you want to use the class in your own code please consider the following points (this is a disclaimer !)

  • The dataset does (by long) not support all possible field-types.
  • The functionality is based on the diffgram structure as found, this structure is not (as far as I know) backed up by some kind of formal specification. Special testing deserve the roworder attribute and the localization settings.
  • New updated versions of the component and these papers will appear on this website.

You are welcome to experiment with the component and any suggestions, remarks, comments, or other feedback will be greatly appreciated. It will all be used in the  updates.

Where are we ?

In this paper we have seen how a Delphi webservice client can work with a webservice which works with XML (diffgram) datasets. All functionality is stored in the GekkoDotNetDataSet component, which is based on Delphi's HTTPrio component.

What's next ?

 

文章来源: http://www.gekko-software.nl/DotNet/Art06.htm

该日志标签: delphi, .net, dataset

delphi如何调用.NET webservice

该日志由 samool 发表于 2007-01-11 09:03:34

假设您已经在.net上建立了自己的webservice,目前只是想在delphi上实现对net上自己的webservice 接口的调用

1)  在你的工程中 new  -> other 选择 webservices 这页

2)  选择其中的 wsdl importer 项

3)  在其中的wsdl source中填入你已经知道的wdsl地址,这里我填入我的地址是
http://192.168.0.123/hello/tijiaosj.asmx?wsdl

4) next后 就自动生成了一个unit

5)  这个unit中包含了你提供的url地址中的所有可用接口
其中 GetXXXXXSoap 这个函数返回了这些接口的class
在业务代码中只要写 GetXXXXXSoap.XXXfunction就可以了

6)  另外提当函数要操作中文的时候,记得修改GetXXXXXSoap,添加这条语句
RIO.HTTPWebNode.UseUTF8InHeader := True; //解决中文乱码问题
呵呵,很简单,对吧

最后,稍微改了一下Delphi生成的接口单元

改动的地方为:

7). 添加接口的执行选项默认为 ioDocument
如果是JAVA 接口, 将执行选项改为 ioLiteral  即可.

修改后的代码如下:
InvRegistry.RegisterInvokeOptions(TypeInfo(XcdsExPortType), ioDocument);

该日志标签: delphi, webservice, .net