惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页
Forbes - Security
Forbes - Security
WordPress大学
WordPress大学
P
Proofpoint News Feed
T
Threat Research - Cisco Blogs
L
LINUX DO - 热门话题
L
Lohrmann on Cybersecurity
Spread Privacy
Spread Privacy
D
Darknet – Hacking Tools, Hacker News & Cyber Security
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
P
Privacy International News Feed
A
About on SuperTechFans
T
Tailwind CSS Blog
I
InfoQ
S
Securelist
云风的 BLOG
云风的 BLOG
罗磊的独立博客
Recent Announcements
Recent Announcements
T
The Exploit Database - CXSecurity.com
B
Blog RSS Feed
V
Visual Studio Blog
Know Your Adversary
Know Your Adversary
The GitHub Blog
The GitHub Blog
Jina AI
Jina AI
腾讯CDC
Cyberwarzone
Cyberwarzone
有赞技术团队
有赞技术团队
AWS News Blog
AWS News Blog
博客园 - 【当耐特】
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
F
Full Disclosure
S
Secure Thoughts
博客园 - 司徒正美
J
Java Code Geeks
Y
Y Combinator Blog
Google Online Security Blog
Google Online Security Blog
GbyAI
GbyAI
N
News and Events Feed by Topic
Help Net Security
Help Net Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Project Zero
Project Zero
T
Tenable Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Tor Project blog
MyScale Blog
MyScale Blog
Scott Helme
Scott Helme
小众软件
小众软件
K
Kaspersky official blog

博客园 - 柠茶

asp.net webapi 参数绑定总结 asp.net webapi 参数绑定总结 javascript引用类型 javascript变量,作用域和内存问题 javascript基本概念 javascript中所谓的“坑”收录 JS调用webservice的两种方式 反射体验(转) 什么是Emit,什么是反射,二者区别到底是什么?(转) 关于可空类型 学习IIS & MVC的运行原理 (转) MVC-READ5(asp.net web from PK asp.net MVC) MVC-READ4 MVC-READ3(视图引擎主要类关系图) MVC-READ2 MVC-READ1 @@ERROR和@@ROWCOUNT的用法 异常以及异常处理框架探析(转) .Net深入学习序列化和反序列化 (转)
可扩展对象模式(转)
柠茶 · 2013-05-25 · via 博客园 - 柠茶

摘要:本文介绍了如何使用WCF中提供的可扩展对象模式扩展HttpApplication,事实上可扩展对象模式的作用远不在此,它可以扩展.NET类库中任何我们想对其进行扩展的对象,或者是一个自定义的类型,都可以使用可扩展对象模式对其进行扩展。

  概述

  HttpApplication对象对于做ASP.NET开发的朋友,我想没有人不熟悉它。在ASP.NET开发中,经常避免不了要在HttpApplication中执行一些操作,如使用了ASP.NET MVC框架,就会在Application_Start 事件中避免不了这样的路由规则配置代码:

protected void Application_Start()
{
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

RouteTable.Routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}

  如果仅仅是这一条,看起来倒不觉的有什么问题,但如果同时在应用程序中使用了工作流,又避免不了在Application_Start出现启动工作流运行时的代码:

protected void Application_Start()
{
// 注册路由规则
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
RouteTable.Routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);

// 启动工作流
WorkflowRuntime workflowRuntime = new WorkflowRuntime("workflowServicesConfig");
ExternalDataExchangeService
externalDataExchangeService = new ExternalDataExchangeService();
workflowRuntime.AddService(externalDataExchangeService);
workflowRuntime.StartRuntime();
}

  试想一下,现在我们仅仅是有了ASP.NET MVC路由规则的配置、WF运行时的启动,如果在应用程序中使用某种DI框架,如微软的Unity,是不是又避免不了要出现这样的容器初始化代码呢?

protected void Application_Start()
{
// 注册路由规则
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
RouteTable.Routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);

// 启动工作流
WorkflowRuntime workflowRuntime
= new WorkflowRuntime("workflowServicesConfig");
ExternalDataExchangeService externalDataExchangeService
= new ExternalDataExchangeService();
workflowRuntime.AddService(externalDataExchangeService);
workflowRuntime.StartRuntime();

// 初始化DI容器
IContainerContext repositoryContainer
= ContainerManager.GetContainer("repositoryContainer");
repositoryContainer.Initialize();
}

  再看看Application_Start事件中的代码,有ASP.NET MVC的工作,有WF的工作,也有Unity的工作,不知道将来还会有什么?这些原本互相之间没有任何联系的代码,现在却同时堆在了一起,当每一部分(或者说每一个框架)变化的时候,都会涉及到Application_Start中代码的修改,显然违反了OCP原则。那么有没有一种机制,让这些互不相干的模块之间互相独立,各自发生变化时不影响对HttpApplication?此时我们就需要对HttpApplication进行扩展,提供一个扩展点,让其他模块的程序附加到HttpApplication上面。

  可扩展对象模式

  我们知道WCF提供了非常完美的扩展机制,几乎在服务执行过程中的每一个环节上都提供有扩展点,如ServiceHostBase、OperationContext、InstanceContext、IContextChannel,这些对象都属于可扩展对象,它们都通过Extensions属性获取用于所有扩展的集合。我们能不能使用这种方式对HttpApplication也进行扩展呢,答案自然是肯定的。查阅一下MSDN就会知道在System.ServiceModel命名空间下面提供了这样的一组接口:IExtensibleObject、IExtension和IExtensionCollection,这是可扩展对象模式中最重要的三个接口,也只有这三个接口。

  IExtensibleObject自然是定义了可扩展对象,即我们要对谁进行扩展,它的定义非常简单,仅仅是提供了一个只读的属性Extensions,用来提供所有扩展对象的集合,如下代码所示:

public interface IExtensibleObject<T> where T : IExtensibleObject<T>
{
IExtensionCollection<T> Extensions { get; }
}

  IExtension定义了扩展对象的契约,使对象可以通过聚合扩展另一个对象(此处的另一个对象,就是指上面所讲的扩展宿主IExtensibleObject),在IExtension中定义了两个非常重要的方法Attach和Detach方法,分别用来提供聚合或解聚的通知。

public interface IExtension<T> where T : IExtensibleObject<T>
{
void Attach(T owner);
void Detach(T owner);
}

  当一个扩展对象IExtension附加到可扩展对象的扩展集合中时,它的Attach方法将会被调用;反之如果从集合中移除一个扩展对象时,它的Detach方法会被调用。这一点我们可以通过Reflector来得到验证,如下代码所示:

protected override void InsertItem(int index, IExtension<T> item)
{
lock (base.SyncRoot)
{
item.Attach(this.owner);
base.InsertItem(index, item);
}
}

protected override void RemoveItem(int index)
{
lock (base.SyncRoot)
{
base.Items[index].Detach(this.owner);
base.RemoveItem(index);
}
}

  最后一个接口是IExtensionCollection,它是IExtension对象的集合。

  对HttpApplication进行扩展

  下面我们就看一下如何使用可扩展对象模式对HttpApplication进行扩展,首先定义可扩展对象,让ExtensibleHttpApplication派生于HttpApplication,并实现了IExtensibleObject接口,泛型的参数类型就是它自身,如下代码所示:

public class ExtensibleHttpApplication : HttpApplication,
IExtensibleObject<ExtensibleHttpApplication>
{
private IExtensionCollection<ExtensibleHttpApplication> _extensions;

public ExtensibleHttpApplication()
{
this._extensions = new ExtensionCollection<ExtensibleHttpApplication>(this);
}

public IExtensionCollection<ExtensibleHttpApplication> Extensions
{
get
{
return this._extensions;
}
}
}

  有了可扩展的HttpApplication之后,需要在HttpApplication中实现任何功能,都可以作为一个扩展附加到ExtensibleHttpApplication上去,如实现ASP.NET MVC路由,可以定义一个如下代码所示的扩展对象:

public class MvcHttpApplication : IExtension<ExtensibleHttpApplication>
{
public void Attach(ExtensibleHttpApplication owner)
{
RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

RouteTable.Routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}

public void Detach(ExtensibleHttpApplication owner)
{
//nothing
}
}

  同样如果要在HttpApplication中启动Workflow,可以再针对Workflow定义一个扩展对象,如下示例代码所示:

public class WorkflowHttpApplication : IExtension<ExtensibleHttpApplication>
{
private WorkflowRuntime workflowRuntime;
public void Attach(ExtensibleHttpApplication owner)
{
workflowRuntime = new WorkflowRuntime("workflowServicesConfig");
ExternalDataExchangeService externalDataExchangeService
= new ExternalDataExchangeService();
workflowRuntime.AddService(externalDataExchangeService);
workflowRuntime.StartRuntime();
}

public void Detach(ExtensibleHttpApplication owner)
{
workflowRuntime.StopRuntime();
}
}

  我们已经定义好了相应的扩展对象,只需要在相应的HttpApplication把扩展对象附加到ExtensibleHttpApplication上即可,修改Global.asax中的代码如下所示:

public class MvcApplication : ExtensibleHttpApplication
{
protected void Application_Start()
{
this.Extensions.Add(new MvcHttpApplication());
this.Extensions.Add(new WorkflowHttpApplication());
}
}

  现在代码是不是看起来优雅多了?现在如果要在Application_Start中,添加另外一些执行代码,只需要编写相应的扩展对象,并将其添加到Extension集合中即可。也许有朋友会问,这样每添加一些新的代码,还是要修改Application_Start中的代码啊?别忘了,可以通过配置可以解决这个问题,WCF中的扩展不也是可以采用配置方式实现,不是吗?同样,如果我们需要在Application_End事件中释放某些对象,可以直接从扩展集合中移除它,此时将会调用它的Detach方法。

  总结

  本文介绍了如何使用WCF中提供的可扩展对象模式扩展HttpApplication,事实上可扩展对象模式的作用远不在此,它可以扩展.NET类库中任何我们想对其进行扩展的对象,或者是一个自定义的类型,都可以使用可扩展对象模式对其进行扩展。