c# WebService创建与调用
一、前言
WebService
,顾名思义就是基于Web的服务。它使用Web(HTTP)方式,接收和响应外部系统的某种请求。从而实现远程调用。
我们可以调用互联网上查询天气信息Web服务,然后将它嵌入到我们的程序(C/S或B/S程序)当中来,当用户从我们的网点看到天气信息时,他会认为我们为他提供了很多的信息服务,但其实我们什么也没有做,只是简单调用了一下服务器上的一段代码而已。
ISO的七层模型 : 物理层、数据链路层、网络层、传输层、表示层、会话层、应用层
Socket访问 : Socket属于传输层,它是对Tcp/ip协议的实现,包含TCP/UDP,它是所有通信协议的基础,Http协议需要Socket支持,以Socket作为基础
Socket通信特点:
- 开启端口,该通信是 长连接的通信 ,很容易被防火墙拦截,可以通过心跳机制来实现 ,开发难度大 传输的数据一般是字符串 ,可读性不强
- socket端口不便于推广
- 性能相对于其他的通信协议是最优的
Http协议访问 : 属于应用层的协议,对Socket进行了封装
- 跨平台
- 传数据不够友好
- 对第三方应用提供的服务,希望对外暴露服务接口问题
- 数据封装不够友好 :可以用xml封装数据
- 希望给第三方应用提供web方式的服务 (http + xml) = web Service
二、webService相关术语
1.XML
Extensible Markup Language -扩展性标记语言
- XML,用于传输格式化的数据,是Web服务的基础。
- namespace-命名空间。
- xmlns=“http://itcast.***” 使用默认命名空间。
- xmlns:itcast=“http://itcast.***”使用指定名称的命名空间。
2. WSDL
WebService Description Language – Web服务描述语言。
- 通过XML形式说明服务在什么地方-地址。
- 通过XML形式说明服务提供什么样的方法 – 如何调用。
3. SOAP
Simple Object A***ess Protocol –简单对象访问协议
- SOAP作为一个基于XML语言的协议用于有网上传输数据。
- SOAP = 在HTTP的基础上+XML数据。
- SOAP是基于HTTP的。
SOAP的组成如下:
- Envelope – 必须的部分。以XML的根元素出现。
- Headers – 可选的。
- Body – 必须的。在body部分,包含要执行的服务器的方法。和发送到服务器的数据。
三、创建
新建项目,选择 “ASP.*** Web应用程序(.*** Framework)”。
填写好项目名称、选择项目位置以及所使用的框架,然后点击创建。
选择一个空模板,去掉为https配置选项,然后创建。
打开解决方案资源管理器-右键创建的web项目-添加-新建项-添加 web 服务(AMSX)
。
默认的是HelloWorld方法,自己可以添加几个方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
namespace webServiceServer
{
/// <summary>
/// WebService1 的摘要说明
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.***ponentModel.ToolboxItem(false)]
// 若要允许使用 ASP.*** AJAX 从脚本中调用此 Web 服务,请取消注释以下行。
// [System.Web.Script.Services.ScriptService]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
[WebMethod(Description = "求和的方法")]
public double addition(double i, double j)
{
return i + j;
}
[WebMethod(Description = "求差的方法")]
public double subtract(double i, double j)
{
return i - j;
}
[WebMethod(Description = "求积的方法")]
public double multiplication(double i, double j)
{
return i * j;
}
[WebMethod(Description = "求商的方法")]
public double division(double i, double j)
{
if (j != 0)
return i / j;
else
return 0;
}
}
}
启动项目。在上面我们可以看到我们所写的五个方法,我选择其中一个点进去,点击调用后我们可以看到输出了“4”。
到这里,就创建好了一个服务了。
四、调用
4.1 添加引用的方式
新建项目-添加-服务引用,打开刚刚启动的网站,复制这个地址粘贴到服务引用中。
接下来点击高级,添加Web 引用(W)-在打开的界面中的URL中输入刚刚复制的网址-点击蓝色箭头-添加引用,即可在解决方案资源管理器中看到我们所添加的服务引用。
这样引用就添加好了,那我们现在就开始使用吧。
直接运行一下点击按钮,看看结果
调用成功~
4.2 动态代理的方式
新建一个代理类
using System;
using System.CodeDom;
using System.CodeDom.***piler;
using System.IO;
using System.***;
using System.Text;
using System.Web;
using System.Web.Caching;
using System.Web.Services.Description;
using System.Xml.Serialization;
namespace webServiceClient
{
public class WebServiceHelper
{
public static void CreateWebServiceDLL(string url, string className, string methodName, string filePath)
{
// 1. 使用 WebClient 下载 WSDL 信息。
WebClient web = new WebClient();
//Stream stream = web.OpenRead(url + "?WSDL");
//CertificateTrust.SetCertificatePolicy();//证书出现问题时调用此代码//未能为 SSL/TLS 安全通道建立信任关系
Stream stream = web.OpenRead(url);
// 2. 创建和格式化 WSDL 文档。
ServiceDescription description = ServiceDescription.Read(stream);
//如果不存在就创建file文件夹
if (Directory.Exists(filePath) == false)
{
Directory.CreateDirectory(filePath);
}
if (File.Exists(filePath + className + "_" + methodName + ".dll"))
{
//判断缓存是否过期
var cachevalue = HttpRuntime.Cache.Get(className + "_" + methodName);
if (cachevalue == null)
{
//缓存过期删除dll
File.Delete(filePath + className + "_" + methodName + ".dll");
}
else
{
// 如果缓存没有过期直接返回
return;
}
}
// 3. 创建客户端代理代理类。
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
// 指定访问协议。
importer.ProtocolName = "Soap";
// 生成客户端代理。
importer.Style = ServiceDescriptionImportStyle.Client;
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
// 添加 WSDL 文档。
importer.AddServiceDescription(description, null, null);
// 4. 使用 CodeDom 编译客户端代理类。
// 为代理类添加命名空间,缺省为全局空间。
CodeNamespace nmspace = new CodeNamespace();
Code***pileUnit unit = new Code***pileUnit();
unit.Namespaces.Add(nmspace);
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit);
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
***pilerParameters parameter = new ***pilerParameters();
parameter.GenerateExecutable = false;
// 可以指定你所需的任何文件名。
parameter.OutputAssembly = filePath + className + "_" + methodName + ".dll";
parameter.ReferencedAssemblies.Add("System.dll");
parameter.ReferencedAssemblies.Add("System.XML.dll");
parameter.ReferencedAssemblies.Add("System.Web.Services.dll");
parameter.ReferencedAssemblies.Add("System.Data.dll");
// 生成dll文件,并会把WebService信息写入到dll里面
***pilerResults result = provider.***pileAssemblyFromDom(parameter, unit);
if (result.Errors.HasErrors)
{
// 显示编译错误信息
System.Text.StringBuilder sb = new StringBuilder();
foreach (***pilerError ce in result.Errors)
{
sb.Append(ce.ToString());
sb.Append(System.Environment.NewLine);
}
throw new Exception(sb.ToString());
}
//记录缓存
var objCache = HttpRuntime.Cache;
// 缓存信息写入dll文件
objCache.Insert(className + "_" + methodName, "1", null, DateTime.Now.AddMinutes(5), TimeSpan.Zero, CacheItemPriority.High, null);
}
}
}
调用方法,前面四个配置信息可以写在app.config里,也可以直接代码里写死。
using System;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using webServiceClient.myWebService;
namespace webServiceClient
{
public partial class Form1 : Form
{
public Form1()
{
Initialize***ponent();
}
private void button1_Click(object sender, EventArgs e)
{
WebService1 wb = new WebService1();
double s = wb.subtract(10, 6);
textBox1.Text = s.ToString();
}
private void UseWebService(string xml)
{
// 读取配置文件,获取配置信息
string url = string.Format(@"http://localhost:52264/WebService1.asmx");//ConfigurationManager.AppSettings["WebServiceAddress"];//WebService地址
string className = "WebService1";//ConfigurationManager.AppSettings["ClassName"];//WebService提供的类名
string methodName = "subtract";//ConfigurationManager.AppSettings["MethodName"];// WebService方法名
string filePath = string.Format(@"D:\test\webServiceServer\bin\");//ConfigurationManager.AppSettings["FilePath"];//存放dll文件的地址
// 调用WebServiceHelper
WebServiceHelper.CreateWebServiceDLL(url, className, methodName, filePath);
// 读取dll内容
byte[] filedata = File.ReadAllBytes(filePath + className + "_" + methodName + ".dll");
// 加载程序集信息
Assembly asm = Assembly.Load(filedata);
Type t = asm.GetType(className);
// 创建实例
object o = Activator.CreateInstance(t);
MethodInfo method = t.GetMethod(methodName);
// 参数
//object[] args = { xml };
object[] args = { 10,2};
// 调用访问,获取方法返回值
string value = method.Invoke(o, args).ToString();
//输出返回值
MessageBox.Show($"返回值:{value}");
}
private void button2_Click(object sender, EventArgs e)
{
UseWebService("111");
}
}
}
调用成功~
4.3 HttpWebRequest的方式
新建一个HttpHelper帮助类
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.***;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
namespace webServiceClient
{
public class HttpHelper
{
public static string CallServiceByGet(string strURL)
{
//创建一个HTTP请求
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strURL);
request.Method = "get";
HttpWebResponse response = (System.***.HttpWebResponse)request.GetResponse();
Stream s = response.GetResponseStream();
//转化为XML,自己进行处理
XmlTextReader Reader = new XmlTextReader(s);
Reader.MoveToContent();
string strValue = Reader.ReadInnerXml();
Reader.Close();
strValue = strValue.Replace("<", "<");
strValue = strValue.Replace(">", ">");
return strValue;
}
public static string CallServiceByPost(string strURL, Dictionary<string,string> parameters)
{
//创建一个HTTP请求
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strURL);
//Post请求方式
request.Method = "POST";
//内容类型
request.ContentType = "application/x-www-form-urlencoded";
//设置参数,并进行URL编码
StringBuilder codedString = new StringBuilder();
foreach (string key in parameters.Keys)
{
codedString.Append(HttpUtility.UrlEncode(key));
codedString.Append("=");
codedString.Append(HttpUtility.UrlEncode(parameters[key]));
codedString.Append("&");
}
string paraUrlCoded = codedString.Length == 0 ? string.Empty : codedString.ToString().Substring(0, codedString.Length - 1);
//string paraUrlCoded = HttpUtility.UrlEncode("ProductId");
//paraUrlCoded += "=" + HttpUtility.UrlEncode(this.textBox1.Text);
byte[] payload;
//将URL编码后的字符串转化为字节
payload = System.Text.Encoding.UTF8.GetBytes(paraUrlCoded);
//设置请求的ContentLength
request.ContentLength = payload.Length;
//发送请求,获得请求流
Stream writer = request.GetRequestStream();
//将请求参数写入流
writer.Write(payload, 0, payload.Length);
//关闭请求流
writer.Close();
//获得响应流
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream s = response.GetResponseStream();
//转化为XML,自己进行处理
XmlTextReader Reader = new XmlTextReader(s);
Reader.MoveToContent();
string strValue = Reader.ReadInnerXml();
Reader.Close();
strValue = strValue.Replace("<", "<");
strValue = strValue.Replace(">", ">");
return strValue;
}
}
}
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Reflection;
using System.Security.Policy;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using webServiceClient.myWebService;
namespace webServiceClient
{
public partial class Form1 : Form
{
public Form1()
{
Initialize***ponent();
}
private void button1_Click(object sender, EventArgs e)
{
WebService1 wb = new WebService1();
double s = wb.subtract(10, 6);
textBox1.Text = s.ToString();
}
private void UseWebService(string xml)
{
// 读取配置文件,获取配置信息
string url = string.Format(@"http://localhost:52264/WebService1.asmx");//ConfigurationManager.AppSettings["WebServiceAddress"];//WebService地址
string className = "WebService1";//ConfigurationManager.AppSettings["ClassName"];//WebService提供的类名
string methodName = "subtract";//ConfigurationManager.AppSettings["MethodName"];// WebService方法名
string filePath = string.Format(@"D:\test\webServiceServer\bin\");//ConfigurationManager.AppSettings["FilePath"];//存放dll文件的地址
// 调用WebServiceHelper
WebServiceHelper.CreateWebServiceDLL(url, className, methodName, filePath);
// 读取dll内容
byte[] filedata = File.ReadAllBytes(filePath + className + "_" + methodName + ".dll");
// 加载程序集信息
Assembly asm = Assembly.Load(filedata);
Type t = asm.GetType(className);
// 创建实例
object o = Activator.CreateInstance(t);
MethodInfo method = t.GetMethod(methodName);
// 参数
//object[] args = { xml };
object[] args = { 10,2};
// 调用访问,获取方法返回值
string value = method.Invoke(o, args).ToString();
//输出返回值
MessageBox.Show($"返回值:{value}");
}
private void button2_Click(object sender, EventArgs e)
{
UseWebService("111");
}
private void button3_Click(object sender, EventArgs e)
{
Dictionary<string, string> parameters = new Dictionary<string, string>();
parameters.Add("i", "5");
parameters.Add("j", "2");
string url = string.Format(@"http://localhost:52264/WebService1.asmx/addition");
var result = HttpHelper.CallServiceByPost(url, parameters);
}
}
}
调用成功~
到这里,我们就把三种调用方式讲完咯。
五、扩展
这里有一些别人写好的服务,我们可以直接调用。
调用别人写好的webService,来体验一把 http://www.webxml.***.***/zh_***/index.aspx