C# WebClient调用WebService
WebClient调用WebService
(文末下载完整代码)
先上代码:
object[] inObjects = new[] { "14630, 14631" };
HttpWebClient wc = new HttpWebClient(2300);
var result1 = WebServiceClientHelper.InvokeWebService("ESBService_TEST", "http://localhost/ESBService/VitalSign.svc?wsdl", "QueryVocabSet", inObjects, wc);
WriteLine(result1.ToString());
public class HttpWebClient : WebClient
{
/// <summary>
/// 初始化需要设置超时时间,以毫秒为单位
/// </summary>
/// <param name="timeout">毫秒为单位</param>
public HttpWebClient(int timeout)
{
Timeout = timeout;
} public int Timeout { get; set; } /// <summary>
/// 重写 GetWebRequest,添加 WebRequest 对象超时时间
/// </summary>
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.Timeout = Timeout;
request.ReadWriteTimeout = Timeout;
return request;
}
}
HttpWebRequest 改造依据:
|
WebClient |
HttpWebRequest |
|
提供用于将数据发送到由 URI 标识的资源及从这样的资源接收数据的常用方法。 |
public class HttpWebRequest : WebRequest, ISerializable |
|
Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.dll |
Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.dll |
protected virtual WebRequest GetWebRequest(Uri address) |
public class HttpWebClient : WebClient |
调用服务处理:
public static object InvokeWebService(string providerName, string url, string methodName, object[] args, WebClient wc = null)
{
object result = null; if (wc == null) wc = new WebClient();
using (wc)
{
using (Stream wsdl = wc.OpenRead(url))
{
var client = GetClient(wsdl, url, methodName, providerName);
client.SetValue("Timeout", wsdl.ReadTimeout);
result = client.InvokeService(args);
}
} return result;
}
形如这样 http://192.168.2.100:8090/services/dududuTest?wsdl 的地址,
返回的是 dududuTest 服务下公开的方法,以流的形式,
代码处理里面需要解读这种流,目前看到的一种方式是,把这个流解读编译成一个动态的dll,利用反射,动态调用方法。

/// <summary>为从具有 <see cref="T:System.String" /> 指定的 URI 的资源下载的数据打开一个可读的流。</summary>
/// <returns>一个 <see cref="T:System.IO.Stream" />,用于从资源读取数据。</returns>
/// <param name="address">以 <see cref="T:System.String" /> 形式指定的 URI,将从中下载数据。</param>
public Stream OpenRead(string address)
{
if (address == null)
throw new ArgumentNullException(nameof (address));
return this.OpenRead(this.GetUri(address));
} /// <summary>为从具有 <see cref="T:System.Uri" /> 指定的 URI 的资源下载的数据打开一个可读的流</summary>
/// <returns>一个 <see cref="T:System.IO.Stream" />,用于从资源读取数据。</returns>
/// <param name="address">以 <see cref="T:System.Uri" /> 形式指定的 URI,将从中下载数据。</param>
public Stream OpenRead(Uri address)
{
if (Logging.On)
Logging.Enter(Logging.Web, (object) this, nameof (OpenRead), (object) address);
if (address == (Uri) null)
throw new ArgumentNullException(nameof (address));
WebRequest request = (WebRequest) null;
this.ClearWebClientState();
try
{
request = this.m_WebRequest = this.GetWebRequest(this.GetUri(address));
Stream responseStream = (this.m_WebResponse = this.GetWebResponse(request)).GetResponseStream();
if (Logging.On)
Logging.Exit(Logging.Web, (object) this, nameof (OpenRead), (object) responseStream);
return responseStream;
}
catch (Exception ex)
{
Exception innerException = ex;
if (innerException is ThreadAbortException || innerException is StackOverflowException || innerException is OutOfMemoryException)
{
throw;
}
else
{
if (!(innerException is WebException) && !(innerException is SecurityException))
innerException = (Exception) new WebException(SR.GetString("net_webclient"), innerException);
WebClient.AbortRequest(request);
throw innerException;
}
}
finally
{
this.CompleteWebClientState();
}
}
类 DefaultWebServiceClient 定义:

public class DefaultWebServiceClient
{
Type _type;
MethodInfo _method;
object _obj; public object InvokeService(object[] args)
{
object proxy = GetProxy();
return _method.Invoke(proxy, args);
} public void SetValue(string fieldName, object value)
{
object proxy = GetProxy();
PropertyInfo field = _type.GetProperty(fieldName);
if (field != null)
field.SetValue(proxy, value);
} public object GetProxy()
{
if (_obj == null)
_obj = Activator.CreateInstance(_type); return _obj;
} public MethodInfo MethodInfo
{
get { return _method; }
} public DefaultWebServiceClient(Stream wsdl, string url, string methodname, string providerName)
{
if (wsdl == null || (wsdl.CanWrite && wsdl.Length == 0))
throw new Exception("Wsdl为空"); try
{
ServiceDescription sd = ServiceDescription.Read(wsdl);
ServiceDescriptionImporter sdi = new ServiceDescriptionImporter();
sdi.AddServiceDescription(sd, "", "");
CodeNamespace cn = new CodeNamespace(string.Format("DefaultWebServiceClient_{0}_{1}", providerName, wsdl.GetHashCode().ToString())); DiscoveryClientProtocol dcp = new DiscoveryClientProtocol();
dcp.DiscoverAny(url);
dcp.ResolveAll();
foreach (object osd in dcp.Documents.Values)
{
if (osd is ServiceDescription) sdi.AddServiceDescription((ServiceDescription)osd, null, null); ;
if (osd is XmlSchema) sdi.Schemas.Add((XmlSchema)osd);
} //生成客户端代理类代码
CodeCompileUnit ccu = new CodeCompileUnit();
ccu.Namespaces.Add(cn);
sdi.Import(cn, ccu);
CSharpCodeProvider csc = new CSharpCodeProvider();
ICodeCompiler icc = csc.CreateCompiler(); //设定编译器的参数
CompilerParameters cplist = new 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"); //编译代理类
CompilerResults cr = icc.CompileAssemblyFromDom(cplist, ccu);
if (true == cr.Errors.HasErrors)
{
System.Text.StringBuilder sb = new StringBuilder();
foreach (CompilerError ce in cr.Errors)
{
sb.Append(ce.ToString());
sb.Append(System.Environment.NewLine);
}
throw new Exception(sb.ToString());
} //生成代理实例,并调用方法
Assembly assembly = cr.CompiledAssembly;
Type type = null;
foreach (Type t in assembly.GetExportedTypes())
{
if (t.GetCustomAttributes(typeof(System.Web.Services.WebServiceBindingAttribute), false).Count() > 0)
{
type = t;
break;
}
} MethodInfo mi = null; if (type == null)
{
throw new Exception("从Wsdl中找不到可调用的类型");
} mi = type.GetMethod(methodname);
if (mi == null)
{
throw new Exception(string.Format("从Wsdl中找不到可调用的方法{0}.{1}", type.Name, methodname));
}
_type = type;
_method = mi;
}
catch (Exception ex)
{
throw new Exception("创建WebService客户端失败!", ex);
}
}
}
WebClient 是一个操作 WebRequest 的类型,相当于一个 worker,它把服务器能提供的内容(资源)都以流的形式返回来,供我们调用,
解读这种流,需要 ServiceDescription 类实例,再将每项加载入 ServiceDescriptionImporter 类的实例中,
再把它编译成能本地使用的组件,动态地调用,相当于运行时加载了一个dll。
(注:三种方法调用 webService https://www.jb51.net/article/190211.htm)
|
验证 1 |
验证 2 |
|
|
新建了一个webClient(服务代理), 它请求的处理对象默认是webRequest, 因为webRequest没有TimeOut属性,于是我继承了webCLient,override处理对象为HttpWebRequest (注,HttpWebRequest 是 WebRequest的子类) |
新建了一个webClient, 它请求的处理对象默认是webRequest |
|
|
结果 |
在完成整个调用当中charles获取了2次http请求,其中: 第一次:在获取wsdl流的时候,请求包是http请求的get方式; 第二次:加载动态dll反射调用方法时,请求包是http请求的post方式; |
同左 |
|
证 |
webClient真的是一个代理,像一个worker,代码上看似在本地动态引用了第三方的dll,但实际上还是http请求 |
就算不写死类型为 HttpWebRequest,识别出来的对象仍然是HttpWebRequest 的实例,这个服务本质提供的就是 http 请求 |
|
待证 |
识别为http请求应该是url的前缀是http的原因,如果是ftp://...那么识别出来就应该是ftpWebRequest |
这种 WebClient 的方式应该只适用于取 wsdl 来处理,
我尝试直接用 HttpWebRequest 用 get 方法取 http://localhost/ESBService/VitalSign.svc?wsdl 的内容,返回了一段服务中的方法说明 xml,
而我试过直接照着第二次包的请求内容来发 HttpWebRequest,并不能成功(报错500内部服务器出错),可能是我入参处理不对。
WebClient 方式和直接发 HttpWebRequest 方式应该是互通的,可以互相转换的,
不过 WebClient 使用 Httpwebrequest 的方式封装了别的处理,某些程度上减少了程序员的工作,总归是数据结构整合的问题,这块就不多研究了。
WebClient封装 HttpWebRequest 的部分内容(头部等),它还提供了一些方法,
这里有一个示例,是异步请求,得到响应后触发事件的适用,不过这个实例比较久远了,2008年的:
https://docs.microsoft.com/zh-cn/archive/blogs/silverlight_sdk/using-webclient-and-httpwebrequest
.Net当中,WebRequest 与 HttpWebRequest 区别,从名字感觉很相似,反编译结果确实是。
|
由客服端构建的(不同协议的)请求发给服务器 |
||||
|
WebRequest |
FtpWebRequest |
FileWebRequest |
HttpWebRequest |
WebSocket |
|
抽象基类 |
继承于WebRequest |
继承于WebRequest |
继承于WebRequest |
抽象基类 |
|
与WebResponse成对存在 |
ftp:// 开头 |
file:// 开头,一般是打开本机文件, 形如: file:///C:/Users/dududu/0209.pdf file://dududu/Share2021/ |
http:// 开头 |
ws:// 开头 wss:// |
|
Websocket主要是javaScript在页面中使用,不需要像http请求那样等待一整个页面文件返回,只取业务数据。 |
||||
放一些地址给观察观察,感知请求和接受的运作模式,各有性格,殊途同归:
http://192.168.8.100:9000/empId=<EmployeeId>&jobId=<JobId>
get 方式,相当于有这样一个格式的服务地址,可以返回一个超文本内容(网页)或者一些某种格式的数据。
(我比较好奇是服务器怎么响应网络,光知道配置总显得苍白)
http://172.18.99.100:8080/yyzx/index.action?userName=<userName>&passWord=<passWord>
有些网址中这样是等价的,应该是哪里(服务配置、架构配置等)处理到了这个逻辑:
http://192.168.29.100:8081/emr/index.php/index/emr/getemr?personid=7321446
http://192.168.29.100:8081/emr/index.php/index/emr/getemr/personid/7321446
附:点击下载完整代码
C# WebClient调用WebService的更多相关文章
- C# 调用webservice 几种办法(转载)
原文地址: http://www.cnblogs.com/eagle1986/archive/2012/09/03/2669699.html //=========================== ...
- C# 调用WebService的3种方式 :直接调用、根据wsdl生成webservice的.cs文件及生成dll调用、动态调用
1.直接调用 已知webservice路径,则可以直接 添加服务引用--高级--添加web引用 直接输入webservice URL.这个比较常见也很简单 即有完整的webservice文件目录如下图 ...
- 调用webservice 总结
最近做一个项目,由于是在别人框架里开发app,导致了很多限制,其中一个就是不能直接引用webservice . 我们都知道,调用webserivice 最简单的方法就是在 "引用" ...
- 动态调用WebService(C#) (非常实用)
通常我们在程序中需要调用WebService时,都是通过“添加Web引用”,让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务.这样是使工作简单了,但是却和提供Web服务的URL.方法名 ...
- 动态调用webservice(部分转载)
动态调用webservice,做个笔记: public class WSHelper { /// < summary> /// 动态调用web服务 /// < /summary> ...
- C# 动态调用webservice
最近项目中,用到动态调用webservice的内容,此处记录下来,留着以后COPY(我们只需要在XML,config文件,或者数据库中配置webservice连接地址和方法名即可使用): using ...
- 动态调用webservice及WCF服务
动态调用web服务,该方法只针对Web service, WCF的服务不行,如果是WCF的就通过工具直接生产代理类,把代理类配置到调用的项目中,通过配置客户端的终结点动态的取实现: 通过Svcutil ...
- C# .NET 动态调用webservice的三种方式
转载自 百度文库 http://wenku.baidu.com/link?url=Q2q50wohf5W6UX44zqotXFEe_XOMaib4UtI3BigaNwipOHKNETloMF4ax4W ...
- WebService – 2.动态调用WebService
在本节课程中,将演示如何通过程序动态添加.调用.编译.执行WebService并返回结果. WebService动态调用示意图 WebService相关知识 代码文档对象模型CodeDom的使用 编程 ...
- 用C#通过反射实现动态调用WebService 告别Web引用
我们都知道,调用WebService可以在工程中对WebService地址进行WEB引用,但是这确实很不方便.我想能够利用配置文件灵活调用WebService.如何实现呢? 用C#通过反射实现动态调用 ...
随机推荐
- 为什么C#越来越恶心
看看这个 再看这些 more 老子声明个空函数,没有访问数据请改为 static,真是越来越智障 为什么一个活泼的语言越搞越像 C++? C# 发明了各种可爱的小玩意儿,尤其是 async/await ...
- csrf跨站请求伪造与校验策略
目录 一.csrf跨站请求伪造 概念引入 概念讲解 二.csrf校验策略 概念讲解 form表单操作csrf策略 ajax请求csrf策略 三.csrf相关装饰器 一.csrf跨站请求伪造 概念引入 ...
- pip 安装 Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)'))
1.问题 1.1 问题截取 pip install redis -i https://pypi.tuna.tsinghua.edu.cn/simple Looking in indexes: http ...
- unsupported message type: DefaultFullHttpResponse (expected: ByteBuf, FileRegion) 原因以及解决办法
使用netty做http服务器的时候 用android链接 会出现这个错误 原因是http-aggregator顺序有问题 (ps:目前大部分国内博客都是这个排序有点坑爹): 官方文档说明:For c ...
- Windows 记录开机后应用启动慢的问题
最近大屏产品经常报一些开机启动的问题,工厂反馈厂测软件有些模块测试不通过,家里开发测试均发现Launcher等软件首次启动需要加载10多秒. 经过小伙伴们排查,发现是刷母盘后首次开机问题概率比较大.使 ...
- Qt编写地图综合应用27-点聚合
一.前言 在地图上查询结果通常以标记点的形式展现,但是如果标记点较多,不仅会大大增加客户端的渲染时间,让客户端变得很卡,而且会让人产生密集恐惧症.为了解决这一问题,我们需要一种手段能在用户有限的可视区 ...
- Qt开源作品10-代码统计组件
一.前言 代码行数统计主要用来统计项目中的所有文件的代码行数,其中包括空行.注释行.代码行,可以指定过滤拓展名,比如只想统计.cpp的文件,也可以指定文件或者指定目录进行统计.写完这个工具第一件事情就 ...
- Qt编写项目作品26-一维码二维码解析及生成
一.功能特点 支持本地USB摄像头实时解析. 支持网络视频流实时解析. 解码格式支持一维码二维码等各种编码. 可生成一维码二维码,一维码支持EAN_13格式,其他格式可定制. 条形码参数支持宽度.高度 ...
- SpringBoot集成swagger后出现: Failed to start bean ‘documentationPluginsBootstrapper‘的解决方法
SpringBoot集成swagger后出现: Failed to start bean 'documentationPluginsBootstrapper'的编译错误: org.springfram ...
- 在 Development 环境下依赖注入的行为可能有所不同
奇怪的问题 本周被一个奇怪的问题困扰了一天.事情的起因是这样的:在某个 PR 合并后,我拉了最新代码,但是在我本地F5调试始终报错.示例代码如下: public interface Interface ...