Advanced .NET Remoting: 第 9 章 4.改变编程模型
Advanced .NET Remoting: 第 9 章
4.改变编程模型
前面的所有连接器在 .NET Remoting 应用程序的服务器端和客户端两方面增强功能。可插拔的连接器架构不仅支持创建连接器,它还改变了编程模型的多个方面。例如,在第 5 章,你已经见到了为了传递像用户名和口令这样的认证凭据,导致手工修改每个对象的通道连接器的属性。
CustomerManager mgr = new CustomerManager();
IDictionary props = ChannelServices.GetChannelSinkProperties(mgr);
props["username"] = "dummyremotinguser";
props["password"] = "12345";
不过,在大多数真实世界的应用中,最好基于每个主机设置这些属性,或根据目标对象的基础 URL 设置它们。在理想情况下,使用配置文件或代码可以做到这一点,如以下示例所示:
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="http">
<clientProviders>
<formatter ref="soap" />
<provider type="UrlAuthenticationSink.UrlAuthenticationSinkProvider, UrlAuthenticationSink">
<url
base="http://localhost"
username="DummyRemotingUser"
password="12345"
/>
<url
base="http://www.somewhere.org"
username="MyUser"
password="12345"
/>
</provider>
</clientProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
当使用代码进行设置的时候,你可以简化配置文件中使用的 <url> 条目,使用下面的代码来达到相同的目的。
UrlAuthenticator.AddAuthenticationEntry(
"http://localhost",
"dummyremotinguser",
"12345");
UrlAuthenticator.AddAuthenticationEntry(
"http://www.somewhere.org",
"MyUser",
"12345");
不过,默认并不支持这种方式。可以通过使用自己定制实现的 IClientChannelSink 来轻松实现。
在真正处理连接器之前,你必须编写一个助理类,它提供静态方法用来存储和提取针对基础 URL 的验证条目。所有的条目以 ArrayList 的形式存储,可以通过提供给方法 GetAuthenticationEntry() 方法的 URL 参数来提取。另外,如果对于特定的基础 URL 来说,没有匹配的话,将返回默认的认证信息。助理类如列表 13-17 所示。
列表 13-17 存储用户名和口令的 UrlAuthenticator 助理类
using System;
using System.Collections;
namespace UrlAuthenticationSink
{
internal class UrlAuthenticationEntry
{
internal String Username;
internal String Password;
internal String UrlBase;
internal UrlAuthenticationEntry (String urlbase,
String user,
String password)
{
this.Username = user;
this.Password = password;
this.UrlBase = urlbase.ToUpper();
}
}
public class UrlAuthenticator
{
private static ArrayList _entries = new ArrayList();
private static UrlAuthenticationEntry _defaultAuthenticationEntry;
public static void AddAuthenticationEntry(String urlBase,
String userName,
String password)
{
_entries.Add(new UrlAuthenticationEntry(
urlBase,userName,password));
}
public static void SetDefaultAuthenticationEntry(String userName,
String password)
{
_defaultAuthenticationEntry = new UrlAuthenticationEntry(
null,userName,password);
}
internal static UrlAuthenticationEntry GetAuthenticationEntry(String url)
{
foreach (UrlAuthenticationEntry entr in _entries)
{
// check if a registered entry matches the url-parameter
if (url.ToUpper().StartsWith(entr.UrlBase))
{
return entr;
}
}
// if none matched, return the default entry (which can be null as well)
return _defaultAuthenticationEntry;
}
}
}
连接器本身调用其中的方法来检查对于当前消息的 URL 来说,是否存在一个认证条目。然后,它遍历连接器调用链,直到最后一个传输通道连接器,在这里设置包含正确用户名和口令的属性。最终,为该对象的连接器设置一个标志,以便该逻辑对于一个连接器链条来说只应用一次。该连接器的完整代码如下列表 13-18 所示。
列表 13-18 UrlAuthenticationSink
using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using System.IO;
namespace UrlAuthenticationSink
{
public class UrlAuthenticationSink: BaseChannelSinkWithProperties,
IClientChannelSink
{
private IClientChannelSink _nextSink;
private bool _authenticationParamsSet;
public UrlAuthenticationSink(IClientChannelSink next)
{
_nextSink = next;
}
public IClientChannelSink NextChannelSink
{
get {
return _nextSink;
}
}
public void AsyncProcessRequest(IClientChannelSinkStack sinkStack,
IMessage msg,
ITransportHeaders headers,
Stream stream)
{
SetSinkProperties(msg);
// don't push on the sinkstack because this sink doesn't need
// to handle any replies!
_nextSink.AsyncProcessRequest(sinkStack,msg,headers,stream);
}
public void AsyncProcessResponse(
IClientResponseChannelSinkStack sinkStack,
object state,
ITransportHeaders headers,
Stream stream)
{
// not needed
}
public Stream GetRequestStream(IMessage msg,
ITransportHeaders headers)
{
return _nextSink.GetRequestStream(msg, headers);
}
public void ProcessMessage(IMessage msg,
ITransportHeaders requestHeaders,
Stream requestStream,
out ITransportHeaders responseHeaders,
out Stream responseStream)
{
SetSinkProperties(msg);
_nextSink.ProcessMessage(msg,requestHeaders,requestStream,
out responseHeaders,out responseStream);
}
private void SetSinkProperties(IMessage msg)
{
if (! _authenticationParamsSet)
{
String url = (String) msg.Properties["__Uri"];
UrlAuthenticationEntry entr =
UrlAuthenticator.GetAuthorizationEntry(url);
if (entr != null)
{
IClientChannelSink last = this;
while (last.NextChannelSink != null)
{
last = last.NextChannelSink;
}
// last now contains the transport channel sink
last.Properties["username"] = entr.Username;
last.Properties["password"] = entr.Password;
}
_authenticationParamsSet = true;
}
}
}
}
相关联的连接器提供器提供 <url> 条目,它们可以在下面的连接器提供器中,通过配置文件指定。
<provider type="UrlAuthenticationSink.UrlAuthenticationSinkProvider,
UrlAuthenticationSink">
<url
base="http://localhost"
username="DummyRemotingUser"
password="12345"
/>
</provider>
连接器提供器将通过 providerData 集合接收到这些条目。集合中包括 SinkProviderData 类型的对象实例。每个 SinkProdiverData 对象包含一个对 properties 的字典,它支持访问这些每个条目中的属性 ( 基础 URL、用户名、口令 )。
当配置文件中的条件设置了基础 URL 的时候,它简单地调用 UrlAuthenticator.AddAuthenticationEntry() 方法。如果没有指定基础 URL,就将这里的用户名和口令设置为默认认证值。该提供器的完整代码如列表 13-19 所示。
列表 13-19 UrlAuthenticationSinkProvider
using System;
using System.Runtime.Remoting.Channels;
using System.Collections;
namespace UrlAuthenticationSink
{
public class UrlAuthenticationSinkProvider: IClientChannelSinkProvider
{
private IClientChannelSinkProvider _nextProvider;
public UrlAuthenticationSinkProvider(IDictionary properties,
ICollection providerData)
{
foreach (SinkProviderData obj in providerData)
{
if (obj.Name == "url")
{
if (obj.Properties["base"] != null)
{
UrlAuthenticator.AddAuthenticationEntry(
(String) obj.Properties["base"],
(String) obj.Properties["username"],
(String) obj.Properties["password"]);
}
else
{
UrlAuthenticator.SetDefaultAuthenticationEntry(
(String) obj.Properties["username"],
(String) obj.Properties["password"]);
}
}
}
}
public IClientChannelSinkProvider Next
{
get {return _nextProvider; }
set {_nextProvider = value;}
}
public IClientChannelSink CreateSink(IChannelSender channel,
string url,
object remoteChannelData)
{
// create other sinks in the chain
IClientChannelSink next = _nextProvider.CreateSink(channel,
url,
remoteChannelData);
// put our sink on top of the chain and return it
return new UrlAuthenticationSink(next);
}
}
}
使用该连接器
在需要使用这个连接器的时候,你可以通过在配置文件中简单地将它添加到客户端的连接器链中,如下所示:
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="http">
<clientProviders>
<formatter ref="soap" />
<provider type="UrlAuthenticationSink.UrlAuthenticationSinkProvider,
UrlAuthenticationSink" />
</clientProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>
注意:该连接器是 IClientChannelSink,所以必须放在格式化器 之后
为了对特定的基础 URL 指定一组用户名和密码,现在可以通过将认证信息添加到配置文件中来完成,将一个或者多个 <url> 条件添加到 <provider> 配置节来。
<clientProviders>
<formatter ref="soap" />
<provider type="UrlAuthenticationSink.UrlAuthenticationSinkProvider,
UrlAuthenticationSink">
<url
base="http://localhost"
username="DummyRemotingUser"
password="12345"
/>
</provider>
</clientProviders>
如果你不希望硬编码这些信息,你可以让客户端应用程序的用户提供用户名和密码,然后使用下面的代码来为连接器注册它:
UrlAuthenticator.AddAuthenticationEntry(<url>, <username>, <password>);
为了达到与前面使用配置文件片断中的 <url> 所示的相同效果,你可以如下使用:
UrlAuthenticator.AddAuthenticationEntry(
"http://localhost",
"dummyremotinguser",
"12345");
参考资料
- Advanced .NET Remoting
- PDF 样张 - 第 13 章 扩展 .NET Remoting
- Source Code of Advanced .NET Remoting
- 在线阅读:第 13 章 扩展 .NET Remoting
- 示例代码下载链接
- 全书示例代码下载
Advanced .NET Remoting: 第 9 章 4.改变编程模型的更多相关文章
- Storm 第一章 核心组件及编程模型
1 流式计算 流式计算:数据实时产生.实时传输.实时计算.实时展示 代表技术:Flume实时获取数据.Kafka/metaq实时数据存储.Storm/JStorm实时数据计算.Redis实时结果缓存. ...
- 第3章 窗口与消息_3.1Windows编程模型
第3章窗口与消息 3.1 Windows_编程模型 (1)窗口程序的运行过程 ①设计窗口 ②注册窗口类(RegisterClassEx).在注册之前,要先填写RegisterClassEx的参 ...
- 第二章 C语言编程实践
上章回顾 宏定义特点和注意细节 条件编译特点和主要用处 文件包含的路径查询规则 C语言扩展宏定义的用法 第二章 第二章 C语言编程实践 C语言编程实践 预习检查 异或的运算符是什么 宏定义最主要的特点 ...
- 简学Python第六章__class面向对象编程与异常处理
Python第六章__class面向对象编程与异常处理 欢迎加入Linux_Python学习群 群号:478616847 目录: 面向对象的程序设计 类和对象 封装 继承与派生 多态与多态性 特性p ...
- [Real World Haskell翻译]第20章 Haskell系统编程
第20章 Haskell系统编程 到目前为止,我们已经讨论了大多数的高层次的概念.Haskell也可以用于较低级别的系统编程.很可能是用haskell编写出底层的与操作系统接口的程序. 在本章中,我们 ...
- 20190827 On Java8 第十四章 流式编程
第十四章 流式编程 流的一个核心好处是,它使得程序更加短小并且更易理解.当 Lambda 表达式和方法引用(method references)和流一起使用的时候会让人感觉自成一体.流使得 Java ...
- 第一章 CLR 的执行模型
CLR via C# 读书笔记:第一章 CLR 的执行模型(1) 第Ⅰ部分CLR基础.这部分为三章(第一章:CLR的只想能够模型,第二章:生成.打包.部署和管理应用程序及类型,第三章:共享程序集和强命 ...
- 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条
http://blog.csdn.net/terryzero/article/details/3797782 疯狂JAVA讲义---第十二章:Swing编程(五)进度条和滑动条 标签: swing编程 ...
- 简学Python第三章__函数式编程、递归、内置函数
#cnblogs_post_body h2 { background: linear-gradient(to bottom, #18c0ff 0%,#0c7eff 100%); color: #fff ...
- Linux/Unix系统编程手册 第三章:系统编程概念
本章介绍系统编程的基础概念和一些后续章节用到的函数及头文件,并说明了可移植性问题. 系统调用是受控的内核入口,通过系统调用,进程可以请求内核以自己的名义去执行某些动作,比如创建子进程,执行I/O操作, ...
随机推荐
- 智慧矿山IT智能运维自动化解决方案
矿山企业是国民经济中的重要组成部分,其资源开发和产业链条中涉及的环节与过程非常繁琐和复杂.随着我国矿山企业规模逐年扩大,为了提高其生产效率和降低其生产成本,信息化.数字化建设成为当下矿山企业发展的重要 ...
- 「模拟赛」CSP-S 模拟 11(T2 超详细)
比赛链接 A.玩水 (water) 签到.发现如果要找两条路径的话,能找到的充要条件是存在一个点的上方和左方的字母相同.(即使两条走过的点截然不同的路径也符合,这时终点会成为这个点). 即存在一个位置 ...
- 用 KubeKey 快速离线部署 K8s 与 KubeSphere
作者:尹珉,KubeSphere Ambassador,KubeSphere 社区用户委员会杭州站站长 一.KubeKey 介绍 KubeKey(以下简称 KK) 是一个用于部署 Kubernetes ...
- CKS 认证备考指南
作者:scwang18,主要负责技术架构,在容器云方向颇有研究. 前言 CKA 和 CKS 是 Linux 基金会联合 CNCF 社区组织的云原生技术领域权威的技术水平认证考试,考试采用实操方式进行. ...
- OpenFunction v0.8.0 发布:通过 Dapr Proxy 加速函数启动
相较于其他函数计算项目,OpenFunction 有很多独特的功能,其中之一便是通过 Dapr 与各种后端服务(BaaS)无缝集成.目前 OpenFunction 已经支持了 Dapr 的 pub/s ...
- 小A的组合数
小A的组合数 题目描述 \(C_n^m\)表示组合,组合公式为:\(C_n^m=\frac{n!}{m!\times (n-m)!}\),请你求出\(C_n^m\)的因子个数\(tot\),由于大难会 ...
- 防火墙NAT+DHCP+ACL+ACAP
任务要求: SwitchA作为有线终端网关与DHCP Server,为无线终端与有线终端分配IP地址,并配置ACL访问控制列表控制不同用户的访问权限,客户机只能跟DMZ区域服务器互访,无线访客禁止访问 ...
- Octomap的学习
什么是octomap? RGBD SLAM的目的有两个:估计机器人的轨迹,并建立正确的地图.地图有很多种表达方式,比如特征点地图.网格地图.拓扑地图等等.在<一起做>系列中,我们使用的地图 ...
- 详解 Hough 变换(基本原理与直线检测)
Hough 变换原理与应用 前言: 详细介绍了 Hough 变换的基本思想.基本原理和应用等.其中大多都是自己的理解,难免有偏差,仅供参考. 文章目录 Hough 变换原理与应用 1. 基本概述 1. ...
- CMU15445学习记录
写在开头 我已经深刻意识到找工作的不易,因此想要开始恶补计算机基础知识,以此作为起点 由于考研的时候学过408综合,因此试图逃课CSAPP并直接开始CMU,发表此篇用作记录. 关于底层原理 原理 数据 ...