澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

包括微软,Service的创建和访问

概要说明

电子枢纽全称国家交通运输物流公共信息平台,主要提供物流及生产企业进行物流相关数据交换的标准和API,详细介绍可参考其官网www.logink.org,本文假定阅读者对该平台已有了解,并已成功申请了相应的帐号和数据交换服务。

信用中心是电子枢纽众多数据服务中的一个,提供物流参与者信用信息的上传和查询,包括运输车辆、从业人员等。官方的示例和介绍大多以Java为主,.net的非常少,希望本文可以帮助.net开发人员快速掌握数据交换方式。

电子枢纽的数据服务分为两种,一种称为数据交换,另一种称为服务调用。

数据交换是一种类似电子邮件的行为,可以把电子枢纽看作是一个邮件服务器,发送和接收数据就与收发电子邮件的方式类同。

服务调用就是常规的HTTP请求,主要用于向电子枢纽查询信息,例如对于信用中心来说,可以查询到车辆的运政信息、诚信记录等。

本文主要介绍的是服务调用方式,要调用电子枢纽提供的服务,首先必须确保已经开通了相关服务,开通后还需要获得服务的ID,这些任务都可以从电子枢纽的用户管理中心完成。

在调用服务前,必须获得用户验证的令牌(Access Token),这项工作可通过统一认证服务完成,获得令牌后,方可凭令牌调用相关服务。

为了实现不同系统间的业务数据交换,我们需要访问对方的接口,也需要开放出自己的接口。.Net的web service挺好用的,不管是创建还是调用都是相当容易。

简要地写出一个.NET Remoting的示例

引入服务

电子枢纽的数据接口都是以Web Service提供的,所以在开始编码之前,可以先引入相关的服务,在VS里直接添加服务引用即可,相关的服务地址可以在官网的开放接入中心找到。

值得注意的是,虽然电子枢纽提供的大部分Web Service都可以在VS中直接引入,但还有个别不能采用这种“添加服务引用”的方式,目前已知的就是信用中心服务。对于这种情况,需要在VS中以Web引用的方式来添加,具体方法如下。

右键点击解决方案浏览器中项目或引用(Reference)的节点,在菜单中选择“添加服务引用”(Add Service Reference),在弹出的对话框里点击“高级”(Advanced),再在弹出的服务引用设置对话框里点击“添加Web引用”(Add Web Reference)即可调出添加Web引用的对话框。

图片 1  图片 2

至于为什么要这样,由于我对SOAP和WCF没有太多了解,实在没法回答这个问题,希望这方面的大神可以给出解答。

创建Web Service

  • ###### 添加Web服务(ASMX)

默认的大概就这个样子吧,例子是个很好的东西。

/// <summary>
/// WebService1 的摘要说明
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 
// [System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService
{
    [WebMethod]
    public string HelloWorld()
    {
        return "Hello World";
    }
}
  • ###### 创建Web Method

依葫芦画瓢,添加方法并为方法添加WebMethod特性。当需要实现的服务比较复杂,类型比较多,但是调用比较集中,可以考虑一个Web Method承载多个服务,把服务名包含在参数中,这要可以避免到处都是Web Method,数据格式也比较统一,写说明文档的时候深有感受。

/// <summary>
/// TestService1 把服务名做成一个参数
/// </summary>
/// <param name="service">服务名</param>
/// <param name="data">数据</param>
/// <param name="verifyCode">校验码</param>
/// <returns></returns>
[WebMethod]
public string TestService1(string service,string data,string verifyCode)
{
    return null;
}
/// <summary>
/// TestService2 把服务名包含在主数据内
/// </summary>
/// <param name="data">数据</param>
/// <param name="verifyCode">校验码</param>
/// <returns></returns>
[WebMethod]
public string TestService2(string data,string verifyCode)
{
    return null;
}

这两种方案我也挺纠结的,一扯就多了,最近用了第二种方案做接口有点后悔了,所以我们以第一种方案为例。

访问接口的请求需要验明正身(这里考虑的是用户名密码这种),但本着不传密码本身的思想,数据在发送前需要把数据和密码计算成一个校验码,类似上面的考虑,也有两种方案,贴一个上来。

/// <summary>
/// TestService3 把用户ID做成一个参数
/// </summary>
/// <param name="service">服务名</param>
/// <param name="userId">用户ID</param>
/// <param name="data">数据</param>
/// <param name="verifyCode">校验码</param>
/// <returns></returns>
[WebMethod]
public string TestService3(string service,string userId, string data, string verifyCode)
{
    return null;
}

是否应该写在同一个Web Method中可以看服务类型是不是能够分到一个大类里面,而参数怎样组成可以根据对安全和便捷的要求。对数据安全性要求不高的时候,可以直接用两个参数,一是包含服务名和用户ID在内的主数据,二是可以结合主数据进行身份验证的校验码。

至于主数据的结构,见过JSON和XML,其中XML偏多。不知怎么的,感觉XML与Web Service更般配。但是显然XML结构比JSON更笨重,因为XML每个节点前后都有节点名称,而JSON一个属性一个名称;生成XML格式数据也比生成JSON格式数据麻烦,大部分XML的特别的东西没有体现出来,我们只需要一个简单的统一的数据格式标准而已。
后来遇到另一种XML数据格式的结构,把数据中的变量全部做成XML节点的属性,XML节点变少了,也算是一种方案。

  • ###### 添加调用方法

刚才新添加的Web Service默认支持soap1.1,soap1.2访问方法。如果需要支持POST方法,需要修改config文件,在system.web节点中增加配置。

<system.web>
  <webServices>
    <protocols>
      <add name="HttpGet"/>
      <add name="HttpPost"/>
    </protocols>
  </webServices>
</system.web>

【考点】
.NET Remoting程序的原理,.NET Remoting的基本编写方法。
【出现频率】
★★☆☆☆
【解答】
在VS 2008中添加新的类库项目,并命名为NetRmClass,将所属解决方案命名为NetRm,勾选“创建解决方案的目录”。这样,NetRmClass类库项目目录即属于NetRm解决方案,并可以继续向该解决方案添加更多的其他相关项目。类库项目在这里仅用于创建一个远程对象的类,将项目中的cs文件命名为RmObj,其包含的类型同样为RmObj,编写RmObj.cs如代码13.4所示。

访问代码

引用添加完以后,VS会为我们自动生成好相应的类型,直接使用就可以。

首先是获取令牌,统一验证服务的客户端类型是AuthenServiceClient,实例化以后调用他的authenticate方法,方法签名如下:

authenticate(string applicant, string userid, string password, string resource)

关于这个方法的具体说明,可参考官方说明。

返回值的tokenValid属性指示是否验证成功,如果为true,可通过token属性获取令牌的值。示例代码如下:

 1 private bool Authenticate(LoginkUser user, string resId, out string token)
 2 {
 3     AuthenServiceClient clnt = new AuthenServiceClient();
 4 
 5     var result = clnt.authenticate(user.ExchangeCode, user.ExchangeCode, user.Password, resId);
 6 
 7     if (result.tokenValied)
 8         token = result.token;
 9     else
10         token = null;
11 
12     clnt.Close();
13 
14     return token != null;
15 }

得到令牌以后,就可以直接调用信用中心的查询服务了,VS生成的信用中心服务的客户端类型为LoginkServiceService,实例化后调用它的InterfaceName方法。

genericResult InterfaceName(authentication Authentication, publicInformation PublicInformation, string BusinessInformation)

这个方法没有找到官方的文档,由于各个参数比较复杂,就不一一介绍了(其实我自己也没搞明白),直接照抄下面的示例就可以了。

 1 private string CallCreditService(LoginkUser user, string token, string action, string request)
 2 {
 3     var css = _settings.CreditService;
 4 
 5     Logink.Services.Credit.security security = new Logink.Services.Credit.security();
 6     security.LogisticsExchangeCode = user.ExchangeCode;
 7     security.UserTokenID = token;
 8 
 9     Logink.Services.Credit.authentication authentication = new Logink.Services.Credit.authentication();
10     authentication.UserName = user.ExchangeCode;
11     authentication.UserPassword = user.Password;
12     authentication.ServiceId = css.ResourceId;
13     authentication.UserId = user.ExchangeCode;
14 
15     Logink.Services.Credit.publicInformation publicInformation = new Logink.Services.Credit.publicInformation();
16     publicInformation.ServiceType = "3";
17     publicInformation.ActionType = action;
18 
19     Logink.Services.Credit.LoginkServiceService service = new Logink.Services.Credit.LoginkServiceService();
20     service.Url = css.Url;
21     service.Security = security;
22 
23     var result = service.InterfaceName(authentication, publicInformation, request);
24 
25     if (result.ResultCode)
26     {
27         return result.BusinessInformation;
28     }
29     else
30         throw new ExchangeException(result.ExceptionInformationCode, result.ExceptionInformation);
31 }

示例中这个CallCreditService方法已经封装了调用信用中心服务的各种参数,其中action参数表示业务类型,官网有介绍,下面再详细说下request参数。

request参数实际上是个经过Base64编码的XML字符串,XML的内容就是各个传入参数的值,需要注意的是,传入的这个XML串并不是完整的文档,而是根节点以下的内容,千万不要把根节点也传上来,如果你使用XmlDocument来处理传入参数,可以使用根节点的InnerXml属性。

Base64编码相对来说就比较简单了,System.Convert类型直接支持转换为Base64,默认情况下电子枢纽使用的是UTF8编码,在编/解码时不要搞错,否则会查不到数据或出现乱码。

1 private string XmlToBase64(string xml)
2 {
3     if (string.IsNullOrEmpty(xml))
4         return xml;
5 
6     return Convert.ToBase64String(Encoding.Utf8.GetBytes(xml));
7 }

最后,需要处理的是InterfaceName的返回值,返回值的ResultCode指示是否调用成功,如果不成功可通过ExceptionInformationCode属性获取错误代码,否则可以通过BusinessInformation属性获取返回的文本。

返回的文本同样是一个Base64编码的XML字符串,转换成明文以后就可以直接使用了,不过对于明文的处理是一件比较头痛的事,经过多次试验最终摸索出以下的规律。

文本为空串:可能是没有查询到相关的内容。

文本不是XML:尽管ResultCode为true,但仍旧可能是出现了错误,文本的内容就是出错信息。

对于这些情况,我们的程序都应该进行相应的处理。

 1 public XmlDocument QueryCredit(QueryParameters parameters)
 2 {
 3     if (parameters == null)
 4         throw new ArgumentNullException(nameof(parameters));
 5 
 6     AccessToken token;
 7     string data;
 8     bool forceRenewToken = false;
 9 
10     retry:
11 
12     // 通过统一验证服务获取用户的访问令牌
13     token = GetToken(_user, _settings.CreditService.ResourceId, forceRenewToken);
14 
15     // 将传入参数序列化为XML
16     data = parameters.GetXml();
17     // 对XML转换为BASE64编码
18     data = XmlToBase64(data);
19 
20     try
21     {
22         // 调用信用中心的Web Service
23         data = CallCreditService(_user, token.Value, parameters.ActionName, data);
24     }
25     catch(ExchangeException ee)
26     {
27         // 判断是否需要更新令牌
28         if (ee.IsTokenInvalid && !forceRenewToken)
29         {
30             forceRenewToken = true;
31             goto retry;
32         }
33         else
34             throw;
35     }
36 
37     if (!string.IsNullOrEmpty(data))
38     {
39         // 返回的内容已做了BASE64编码处理,将它转换为XML。
40         data = Base64ToXml(data);
41 
42         // 部分情况下平台返回的可能是一串错误信息而非XML,因此对不是"<"开头的直接按错误信息处理。
43         if (data[0] == '<')
44         {
45             XmlDocument doc = new XmlDocument();
46             doc.LoadXml(data);
47 
48             return doc;
49         }
50         else
51             throw new ExchangeException(data);
52     }
53     else
54     {
55         // 如果返回的内容为空,可能是没有查到相关数据。
56         throw new ExchangeException("110008", "暂时没有查到相应数据");
57     }
58 
59 }

到些为止,调用信用中心服务所需的代码都已经大致做了介绍,把它们串起来以后就形成了一个完整的程序,全部源代码请点击此处。由于我的电脑上装的是VS2015,低版本的VS可能没办法打开,实在抱歉。

访问Web Service

浏览器打开Web Service的路径,可以看到访问方法示例,soap1.1,soap1.2,post,照着样子拼凑出来就可以调用。另外可以添加web引用,添加服务引用,制作dll的方式调用。
以下的例子用的Web Service创建为

/// <summary>
/// TestService 的摘要说明
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消注释以下行。 
// [System.Web.Script.Services.ScriptService]
public class TestServices : System.Web.Services.WebService
{

    [WebMethod]
    public string HelloWorld(string name)
    {
        return "Hello " name;
    }
}

忍不住说一句,python调用不要太容易,顿时感觉写C#好苦逼

from suds.client import Client  
url = 'http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl"  
client = Client(url)
result = client.service.HelloWorld('A')
print(result)
  • ###### 添加服务引用

添加服务引用之后,config文件内将在configuration节点下自动生成

<system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="TestServicesSoap" />
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://localhost:1029/TestServices.asmx" binding="basicHttpBinding"
            bindingConfiguration="TestServicesSoap" contract="ServiceReference1.TestServicesSoap"
            name="TestServicesSoap" />
    </client>
</system.serviceModel>

调用

ServiceReference1.TestServicesSoapClient client = new ServiceReference1.TestServicesSoapClient();
string content = client.HelloWorld("甲");

当前项目直接调用不会有什么问题
如果项目A添加了服务引用,项目B引用项目A,会出现类似于下面这种错误:

在 ServiceModel 客户端配置部分中,找不到引用协定“ServiceReference1.TestServicesSoap”的默认终结点元素。这可能是因为未找到应用程序的配置文件,或者是因为客户端元素中找不到与此协定匹配的终结点元素。

解决办法,将刚才那段配置信息复制到项目B的config文件中就可以了。

如果要在项目B中直接调用项目A中的服务引用,需要在项目B中添加引用system.serviceModel。

  • ###### 添加Web引用

添加Web引用之后,config文件内将在configuration节点下自动生成

<applicationSettings>
    <service.Properties.Settings>
        <setting name="service_localhost_TestServices" serializeAs="String">
            <value>http://localhost:1029/TestServices.asmx</value>
        </setting>
    </service.Properties.Settings>
</applicationSettings>

调用

WebService1.TestServices service = new WebService1.TestServices();
//service.Url = "http://localhost:1031/TestServices.asmx";
string content = service.HelloWorld("甲");

当项目B调用项目A时将不需要修改配置文件

  • ###### 制作成dll文件

使用vs命令行wsdl制作dll,步骤:
1.浏览器打开http://localhost:1029/TestServices.asmx?wsdl,并保存为.wsdl文件,如:TestServices.wsdl
2.执行命令wsdl /namespace:Services.Test TestServices.wsdl,将生成文件TestServices.cs
3.执行命令csc /out:Services.TestServices.dll /t:library TestServices.cs,将生成文件Services.TestServices.dll

访问Web Service直接引用Services.TestServices.dll,干净利落。

Services.Test.TestServices service = new Services.Test.TestServices();
//service.Url = "http://localhost:1031/TestServices.asmx";
string content =  service.HelloWorld("甲");

其它非.Net的Web Service制作dll也可以用类似的方案。

当wsdl文件带有wsdl:import时,需要把import的文件也下载下来,否则wsdl命令会执行出错,一个一个找import难免比较麻烦,这里有个取巧的方法,添加web引用或者服务引用都会生成全部的wsdl文件,找到对应目录拷贝出来或者直接定位到对应目录生成dll即可。

  • ###### post方法

用Post方法调用需要注意几点
1.ContentType设置为application/x-www-form-urlencoded
2.Request流用System.Text.Encoding.Default编码
3.Response流用System.Text.Encoding.UTF8解码
4.键值对的值一定要UrlEncode编码

因此简单的访问方式就出来了

string url = "http://localhost:1031/TestServices.asmx"   "/HelloWorld";
string data = "name="   HttpUtility.UrlEncode("甲");
string content;
WebRequest req = HttpWebRequest.Create(url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
using (StreamWriter sw = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.Default))
{
    sw.Write(data);
}
using (StreamReader sr = new StreamReader(req.GetResponse().GetResponseStream(), System.Text.Encoding.UTF8))
{
    content = sr.ReadToEnd();
}
  • ###### 调用动态生成的Web Service

WebService不适合高频动态生成,偶尔需要调用可以用动态生成

public static object InvokeWebService(string url, string methodname, object[] args)
{
    //namespace是需引用的webservices的命名空间
    string @namespace = "client";

    //获取WSDL
    System.Net.WebClient wc = new System.Net.WebClient();
    System.IO.Stream stream = wc.OpenRead(url   "?WSDL");
    System.Web.Services.Description.ServiceDescription sd = System.Web.Services.Description.ServiceDescription.Read(stream);
    string classname = sd.Services[0].Name;
    System.Web.Services.Description.ServiceDescriptionImporter sdi = new System.Web.Services.Description.ServiceDescriptionImporter();
    sdi.AddServiceDescription(sd, "", "");
    System.CodeDom.CodeNamespace cn = new System.CodeDom.CodeNamespace(@namespace);

    //生成客户端代理类代码
    System.CodeDom.CodeCompileUnit ccu = new System.CodeDom.CodeCompileUnit();
    ccu.Namespaces.Add(cn);
    sdi.Import(cn, ccu);

    //设定编译参数
    System.CodeDom.Compiler.CompilerParameters cplist = new System.CodeDom.Compiler.CompilerParameters();
    cplist.GenerateExecutable = false;
    cplist.GenerateInMemory = true;
    cplist.ReferencedAssemblies.Add("System.dll");
    cplist.ReferencedAssemblies.Add("System.XML.dll");
    cplist.ReferencedAssemblies.Add("System.Web.Services.dll");
    cplist.ReferencedAssemblies.Add("System.Data.dll");

    //编译代理类
    Microsoft.CSharp.CSharpCodeProvider csc = new Microsoft.CSharp.CSharpCodeProvider();
    System.CodeDom.Compiler.CompilerResults cr = csc.CompileAssemblyFromDom(cplist, ccu);

    if (cr.Errors.HasErrors)
    {
        //处理错误信息
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        foreach (System.CodeDom.Compiler.CompilerError ce in cr.Errors)
        {
            sb.Append(ce.ToString());
            sb.Append(System.Environment.NewLine);
        }
        throw new Exception(sb.ToString());
    }

    //生成代理实例,并调用方法
    System.Reflection.Assembly assembly = cr.CompiledAssembly;
    Type t = assembly.GetType(@namespace   "."   classname, true, true);
    object obj = Activator.CreateInstance(t);
    System.Reflection.MethodInfo mi = t.GetMethod(methodname);

    return mi.Invoke(obj, args);
}

看不懂没关系,直接调用,好好使用,不要把内存撑着了。

string url = "http://localhost:1031/TestServices.asmx";
string method = "HelloWorld";
string name = "甲";
string content = InvokeWebService(url, method, new object[] { name }) as string;
  • ###### 补充

1.对于接口相同的多套系统,每个系统都对接一遍不现实,只是URL不同。其中web引用和dll都有属性URL,可以修改,服务引用貌似不能修改URL。如果对方系统更新,Web引用和服务引用都可以直接更新,dll不能直接更新,需要重新制作。

2.若是在C#中调用Java的webservice,可能会遇到一个问题,java只能获取到string类型参数的值,int,double等在服务器端得到null。非string类型的属性同时生成两个属性:"属性××"、"属性××Specified"。而"属性××Specified"是一个bool类型,只有这个属性被设置成true时,"属性××"的值才会被序列化成xml传递。因此需要注意修改cs文件,把"属性××Specified"删掉。如果是服务引用和web引用,可以直接找到Reference.cs进行修改,如果是制作dll,需要在生成的cs文件上修改。
第一次遇到这个问题时某人给我的解答:http://www.cnblogs.com/zhbsh/archive/2013/04/22/3035477.html
顺手贴上微软的解释:https://msdn.microsoft.com/zh-cn/library/system.xml.xmlattribute.specified(v=vs.110).aspx

3.如果有留意会发现web引用的Reference.cs文件与wsdl命令生成的cs文件惊人的相似,因此制作dll还有个取巧的方法,先添加web引用,然后csc命令打包成dll。

4.哪天想起再补充

代码13.4  远程对象类定义 :RmObj.cs

相关资源

几个必须加入的QQ群

213604083:平台接入群,这是必加的一个群,有很多平台的管理人员在里面,一些基础的问题可以问问他们,当然还有一点很重要的是群里有开发所需要的许多资源。

383412768:信用接入群,如果要使用信用中心服务,这就是你要找的组织。

363016382:园区通接入群,如果你是为了接入而接入(你懂的),那这里是也是必须的。

601484722:充装数据接入群。

using System;
using System.Windows.Forms;

namespace NetRmClass
{
    public class RmObj : MarshalByRefObject
    {
        //在构造函数中,用提示窗口提示双方用户远程对象创建成功
        public RmObj()
        {
            MessageBox.Show("远程对象已经创建", "提示信息");
        }

        //调用Diss方法,会在服务器端的控制台程序中输出方法参数
        public void Diss(string msg)
        {
            Console.WriteLine("客户端信息:" msg);
        }
        //该方法可返回字符串
        public string Disc()
        {
            return "与服务器端完成通信";
        }
    }
}
将NetRm解决方案中的NetRmClass项目进行编译(VS 2008中选择菜单栏的“项目|生成”命令,快捷键为Crtl F6),即可在该项目目录中的“binDebug”路径下生成编译后的NetRmClass.dll程序集。
在VS 2008中的NetRm解决方案再次添加新的控制台应用程序项目,并命名为NetRmServer。该项目所生成的程序集作为Remoting的服务器端,首先需要添加“NetRmClass.dll”程序集引用,并导入NetRmClass命名空间,编写该项目的Program.cs如代码13.5所示。

代码13.5  Remoting服务器端程序:Program.cs

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using NetRmClass;

namespace NetRmServer
{
    class Program
    {
        //声明TcpServerChannel类型的静态字段channels
        static TcpServerChannel channels;

        static void Main(string[] args)
        {
            //创建新的TcpServerChannel对象,端口号为3000,引用为channels
            channels = new TcpServerChannel(3000);
            //将channels注册到信道服务
            ChannelServices.RegisterChannel(channels, false);
            //创建知名服务类型的对象,传递远程对象的类型、对象URI和激活对象的枚举成员
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(RmObj), "MyUri", WellKnownObjectMode.Singleton);
            //信息提示,当用户输入字符,则结束程序
            Console.WriteLine("======服务器端已启动======");
            Console.Read();
        }
    }
}
添加“NetRmClass.dll”程序集引用后,该程序集的副本即被复制到NetRmServer项目目录中的“binDebug”路径下,以供NetRmServer项目生成的程序集使用。将NetRm解决方案中的NetRmServer项目进行编译,即可在该项目目录中的“binDebug”路径下生成编译后的NetRmServer.exe程序集。
在VS 2008中的NetRm解决方案再次添加新的Windows窗体应用程序项目,并命名为NetRmClient。该项目所生成的程序集作为Remoting的客户端,首先仍然需要添加“NetRmClass.dll”程序集引用,并导入NetRmClass命名空间。在“Form1”窗体的设计视图中添加一个Button控件和TextBox控件,分别命名为“button1”和“textBox1”,编写Form1.cs如代码13.6所示。

代码13.6  Remoting客户端程序:Form1.cs

using System;
using System.Windows.Forms;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using NetRmClass;

namespace NetRmClient
{
    public partial class Form1 : Form
    {
        //声明TcpClientChannel类型的字段channelc
        TcpClientChannel channelc;
        //声明RmObj类型的字段obj
        RmObj obj;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //创建TcpClientChannel对象,引用为channelc
            channelc = new TcpClientChannel();
            //将channels注册到信道服务
            ChannelServices.RegisterChannel(channelc, false);
            //创建远程对象
            obj = (RmObj)Activator.GetObject(typeof(RmObj), "tcp://localhost:3000/MyUri");
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string MyName = textBox1.Text;
            //调用远程对象的Diss方法,并传递用户输入值
            obj.Diss(MyName);
            //调用远程对象的Disc方法,返回值赋值给textBox1控件的“Text”属性
            this.textBox1.Text = obj.Disc();     
        }
    }
};
添加“NetRmClass.dll”程序集引用后,该程序集的副本同样被复制到NetRmClient项目目录中的“binDebug”路径下,以供NetRmClient项目生成的程序集使用。将NetRm解决方案中的NetRmClient项目进行编译,即可在该项目目录中的“binDebug”路径下生成编译后的NetRmClient.exe程序集。
至此,一个简单的.NET Remoting应用解决方案已完成,其中服务器端为控制台程序,客户端为Windows窗体程序。服务器端所指定的位置是“localhost”,也可以根据程序需要更改为IP地址。
【分析】
本题主要考查面试者对Remoting应用原理的认识,该解答并不适宜于直接应用于实际开发。当服务器端程序运行后(即运行NetRmServer.exe),用户在客户端程序中输入一些文本,并单击“button1”按钮,服务器端程序和客户端程序运行效果如图13.4所示。

图13.4  .NET Remoting应用示例
解答所编写的.NET Remoting应用用于在本机上测试,不过已经展示了.NET Remoting技术的基本编写方法。通过示例,可以清楚理解该技术的强大功能以及灵活性,但是需要编程者编写大量的代码,并且需要一致的运行环境支撑。

 

【考点】
对WCF技术的了解,WCF技术的基本内容。
【出现频率】
★★☆☆☆
【解答】
常用的分布式技术有COM 、.NET远程技术(Remoting)、Web Service和微软消息队列服务,WCF技术将这些分布式技术整合为一个高效的API。常用的那些分布式技术只能解决项目开发中某个方面的问题,并且不同技术对平台要求不同。在项目中有时要使用到多种技术从而导致这些技术所提供的服务有重叠之处,并且整个项目的维护复杂性大大增加。WCF技术提供了一个完整统一的方案解决这些问题,它提供了一个用于访问各种分布式技术的通用API,并且增加了很多必要的服务。
【分析】
本题主要考查面试者对.NET Framework新版本中WCF技术的基本认知。公司招聘.NET程序员不一定非要熟练掌握WCF这样的新技术,但是一定会要求所招聘的人才具备对新技术的了解,对新技术探索的好奇心。本题即为这样的目的而设,难度不大,只要面试者对新技术有一定程度的了解,经过短时间的培训即可掌握,其考查重点在于面试者的知识广度。

 

 

【考点】
.NET Remoting技术相对于Web Service的优势和劣势。
【出现频率】
包括微软,Service的创建和访问。★★★☆☆
【解答】
q      Remoting技术可以灵活地定义其所基于的协议,比如HTTP协议和TCP协议。在实际开发中,Remoting一般使用TCP协议,这样可保证在保持状态的情况下,获取比Web Service更好的性能,而Web Service默认情况下是没有状态的。
q      Remoting技术不是行业标准,而Web Service是行业标准,并可能成为下一代网络数据交换的核心组成部分。
q      Remoting技术可用.NET的Windows窗体程序或Windows服务进行启动,也可以使用IIS部署,而Web Service则必须通过IIS之类的服务启动。
q      在VS 2008等.NET开发环境中,专门对Web Service的调用进行了封装,可以直接通过添加Web引用或服务引用调用Web Service,节约大量代码。而Remoting需要编写更多代码,开发效率较低。
q      .NET Remoting的通信要求双方运行相同的平台框架,如.NET Remoting需要客户端和服务器端安装.NET Framework。而WebService是平台独立的,可跨语言(支持XML的语言)互动。
【分析】
本题考查面试者的数据库相关的ASP.NET开发经验,.NET Remoting与WebService有所不同,Remoting技术支持HTTP以及TCP信道,而且不仅能传输XML格式的SOAP包,也可以传输传统意义上的二进制流,这使得Remoting效率更高也更加灵活。Remoting不依赖于IIS,服务器端和客户端可以非常灵活地部署。从某些方面上来讲WebService其实上是.NET Remoting的一种特例。

 

 

【考点】创建Web Service的基本代码。

【出现频率】 ★★★☆☆ 

【解答】在VS 2008中添加新的WEB服务代码模板到WebSvRm项目,并命名为MyWebSv.asmx。这个代码文件实际已经具备了Web Service的基本代码结构,这里编写一个能将小写字母转换为大写字母的Web Service应用。首先编写MyWebSv.asmx.cs如代码13.1所示。 代码13.1 转换大写字母的Web Service:MyWebSv.asmx.cs using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Linq; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Xml.Linq; namespace WebSvRm { //默认命名空间的指定 [WebService(Namespace = "] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class MyWebSv : System.Web.Services.WebService { //声明WebMethod特性,该方法才可以被访问 [WebMethod] public string ConvertWord(string word) { return word.ToUpperInvariant(); } } } 然后在WebSvRm项目中添加WEB引用,地址为“ References目录,这个目录包含有localhost子目录。然后在WebSvRm项目的默认首页,即Default.aspx中调用Web Service以输出结果,首先编写Default.aspx如代码13.2所示。 代码13.2 调用Web Service的页面:Default.aspx 
请输入需要转换大写字母的初始字母或单词: 调用Web Service所返回的结果: 
最后编写Default.aspx.cs如代码13.3所示。 代码13.3 调用Web Service的逻辑代码:Default.aspx.cs using System; using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; namespace WebSvRm { public partial class _Default : System.Web.UI.Page { protected void btn_Click(object sender, EventArgs e) { //获取用户输入值 string txt1 = this.input.Text; //创建MyWebSv对象,引用为WebSv1 localhost.MyWebSv WebSv1 = new localhost.MyWebSv(); //调用WebSv1方法,并传递txt1变量,返回值赋值给txt2 string txt2 = WebSv1.ConvertWord(txt1); //将txt2赋值给output控件的“Text”属性值 this.output.Text = txt2; } } } 打开IE浏览器,在浏览器地址栏输入“ .net framework”到TextBox控件中,然后单击“开始转换”按钮,页面运行效果如图13.2所示。 图13.2 Web Service调用实例

【分析】本题考查面试者利用VS 2008等开发环境创建Web Service应用的基本方法,因为是基本方法,所以不涉及太多概念。实际上,用该方法创建Web Service应用最为简便,其中很多工作已经被VS 2008等开发环境封装,对于很多编程者,这些细节部分是透明的。解答中所创建的Web Service方法非常简单,在调用Web Service方法时,直接添加WEB引用即可。打开添加WEB引用时自动创建的localhost目录,如图13.3所示。 图13.3 添加WEB引用后生成的文件可见,VS 2008的确做了很多工作,自动创建了4个文件,其中MyWebSv.disco文件用于Web Service的静态发现服务,即使用DISCO定位。不过最常用的Web Service发现服务是使用UDDI发现,即向UDDI服务器注册所创建的Web Service,这样整个Internet上的其他用户可以调用该Web Service的功能了。其中的MyWebSv.wsdl是该Web Service的服务描述,以方便调用方了解Web Service的功能等信息。Reference.cs是客户端的代理类,可用于客户端程序以所属平台的方式直接调用Web Service提供的方法等。Reference.map是一个XML文件,映射了所序列化的文件,即*.disco文件和*.wsdl文件。在实际的项目开发中,Web Service的这些细节工作一般由编程者手动编写,这样更适用于不同项目的需求。

 

 

本文由澳门新浦京娱乐场网站发布于www.146.net,转载请注明出处:包括微软,Service的创建和访问