NopCommerce使用Autofac实现依赖注入
NopCommerce的依赖注入是用的AutoFac组件,这个组件在nuget可以获取,而IOC反转控制常见的实现手段之一就是DI依赖注入,而依赖注入的方式通常有:接口注入、Setter注入和构造函数注入。
NopCommerce将所有和Autofac注入相关的工作都放到了EngineContext中,在Global.asax的Application_Start函数的第一句代码即是:
//initialize engine context
EngineContext.Initialize(false);
从这里开始EngineContext的初始化工作,初始化时会创建一个新的NopEngine,参数false指定当NopEngine不为空时是否重新生成一个新的NopEngine。
[MethodImpl(MethodImplOptions.Synchronized)]
public static IEngine Initialize(bool forceRecreate)
{
if (Singleton<IEngine>.Instance == null || forceRecreate)
{
var config = ConfigurationManager.GetSection("NopConfig") as NopConfig;
Debug.WriteLine("Constructing engine " + DateTime.Now);
Singleton<IEngine>.Instance = CreateEngineInstance(config);
Debug.WriteLine("Initializing engine " + DateTime.Now);
Singleton<IEngine>.Instance.Initialize(config);
}
return Singleton<IEngine>.Instance;
}
NopEngine使用单例模式,在整个程序运行期间存在一个实例,代码首先会判断NopEngine是否为空,为空的话则根据web.config中配置的NopConfig节点信息创建一个新的NopEngine实例,然后对该实例进行初始化操作。web.config中的配置信息如下:
<configSections>
<section name="NopConfig" type="Easy.Core.Configuration.NopConfig, Easy.Core" requirePermission="false" />
</configSections>
<NopConfig>
<DynamicDiscovery Enabled="true" />
<Engine Type="" />
<Themes basePath="~/Themes/" />
</NopConfig>
CreateEngineInstance函数中使用new NopEngine()创建了一个NopEngine实例,在NopEngine的构造函数处对Autofac的容器(Container)作了初始化,如下代码:
public NopEngine(EventBroker broker, ContainerConfigurer configurer)
{
var config = ConfigurationManager.GetSection("NopConfig") as NopConfig;
InitializeContainer(configurer, broker, config);
}
private void InitializeContainer(ContainerConfigurer configurer, EventBroker broker, NopConfig config)
{
var builder = new ContainerBuilder(); _containerManager = new ContainerManager(builder.Build());
configurer.Configure(this, _containerManager, broker, config);
}
NopCommerce通过ContainerManager对容器做了一层封装,方便对其他类型的IOC框架的扩充和支持。Configure函数完成了所有依赖的注入,同时查找所有实现了IDependencyRegistrar接口的类,并调用其Register方法,注册内容包括Http context、web helper、controller、data layer、plugin、cache manager、work context、services、settings、event consumers等等。
关于ContainerManager/ContainerConfigurer和IDependencyRegistrar是实现IOC的关键,下面对这两个部分做详细的讨论。
IOC和DI
IOC中文名被称作控制反转(Inversion of Control),DI被称为依赖注入(Dependency Injection),可参考Martin Fowler的这篇文章来了解这两个概念:IoC容器和DependencyInjection模式。使用控制反转模式开发项目流程是先建立接口,然后再实现类,或许有人不习惯这样的开发方法,但在规模较大的软件架构中,这种方法却可以有效的降低类之间的互相依赖的情况,不但能增加架构的弹性,也能有效的降低软件的复杂度。
如果不考虑控制反转的情况,采用直接创建类,并直接在应用层调用该类,如此一来,应用层的对象就会与BLL(业务逻辑层)对象高度依赖,这样的依赖 会导致这两个类无法拆开,从而增加了这个类的维护难度,同时导致了单元测试难以进行。为了解决耦合度问题,从而引入了控制反转的概念。
Autofac介绍
Autofac是一款IOC框架,比较于其他的IOC框架,如Spring.NET、Unity、Castle等,它更显得轻量级,同时保证了高性能。它具有以下优点:
- 和C#语言联系紧密,可以使用C#语言的很多特性,譬如Lambda表达式等;
- 较低的学习曲线,只需了解IoC和DI的概念以及在何时需要使用它们即可;
- XML配置支持;
- 自动装配;
- 与ASP.NET MVC3集成;(Orchard也是使用Autofac实现IOC的)
在MVC3项目中使用Autofac
在MVC3工程中使用Autofac的最好也是最简单的方法是使用NuGet来安装Autofac.Mvc3,安装完成以后,在Global.asax的Application_Start方法中添加如下代码:
- protected void Application_Start()
- {
- var builder = new ContainerBuilder();
- builder.RegisterControllers(typeof(MvcApplication).Assembly);
- var container = builder.Build();
- DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
- // Other MVC setup...
这样就开启了Controller的依赖注入功能。其中的DependencyResolver是一个全局静态类,MVC3提供了对依赖注入的支 持,SetResolver函数用于设置使用哪个Resolver(解析器)来进行依赖注入,这里使用的是Autofac的依赖注入解析器。如果要使用自 己的解析器,必须在这里使用SetResolver函数设置。
1. 注册Controller
可以使用下面的方法对特定的Controller进行注册:
- var builder = new ContainerBuilder();
- builder.RegisterType<HomeController>().InstancePerRequest();
- 同时可以使用Autofac提供的RegisterControllers扩展方法来对程序集中所有的Controller一次性的完成注册:
- var builder = new ContainerBuilder();
- builder.RegisterControllers(Assembly.GetExecutingAssembly());
2. 注册Model Binder
与控制器的注册类似,模型绑定也可以再Global.asax.cs中注册。您可以通过如下操作完成整个程序集的注册:
- var builder = newContainerBuilder();
- builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
- builder.RegisterModelBinderProvider();
您也必须记住使用RegisterModelBinderProvider扩展方法来注册RegisterModelBinderProvider。这个方法用是Autofac对IModelBinderProvider接口的实现。
因为RegisterModelBinders扩展方法通过扫描程序集来添加模型绑定的,所以您需要指定IModelBuilder注册的目标类是什么类型。
- [ModelBinderType(typeof(string))]
- public class StringBinder : IModelBinder
- {
- public override object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)
- {
- //do implementation here
- }
- }
多行的ModelBuilderTypeAttribute实例可以添加到需要对个类型注册的类中。
3. 注入HTTP抽象类
- HttpContextBase
- HttpRequestBase
- HttpResponseBase
- HttpServerUtilityBase
- HttpSessionStateBase
- HttpApplicationStateBase
- HttpBrowserCapabilitiesBase
- HttpCachePolicyBase
- VirtualPathProvider
- builder.RegisterModule(newAutofacWebTypesModule());
4. 注入View page
- builder.RegisterSource(newViewRegistrationSource());
- public abstract class CustomViewPage : WebViewPage
- {
- public IDependencyDependency { get; set; }
- }
- public abstract class CustomViewPage : ViewPage
- {
- public IDependencyDependency { get; set; }
- }
- @inherits Example.Views.Shared.CustomViewPage
- <%@ PageLanguage="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="Example.Views.Shared.CustomViewPage" %>
5. 对Filter Attribute进行属性注入
- ContainerBuilder builder = new ContainerBuilder();
- builder.RegisterControllers(Assembly.GetExecutingAssembly());
- builder.Register(c => new Logger()).As<ILogger>().InstancePerHttpRequest();
- builder.RegisterFilterProvider();
- IContainer container = builder.Build();
- DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
- public class CustomActionFilter : ActionFilterAttribute
- {
- public ILogger Logger { get; set; }
- public override void OnActionExecuting(ActionExecutingContext filterContext)
- {
- Logger.Log("OnActionExecuting");
- }
- }
- public class CustomAuthorizeAttribute : AuthorizeAttribute
- {
- public ILogger Logger { get; set; }
- protected override bool AuthorizeCore(HttpContextBase httpContext)
- {
- Logger.Log("AuthorizeCore");
- return true;
- }
- }
- [CustomActionFilter]
- [CustomAuthorizeAttribute]
- public ActionResult Index()
- {
- // ...
- }
- 关于Autofac更多的信息,可以参考autofac在google code上的wiki文档:http://code.google.com/p/autofac/wiki/Mvc3Integration
NopCommerce是如何使用Autofac实现依赖注入的?
NopCommerce将所有和Autofac注入相关的工作都放到了EngineContext中,在Global.asax的Application_Start函数的第一句代码即是:
- //initialize engine context
- EngineContext.Initialize(false);
从这里开始EngineContext的初始化工作,初始化时会创建一个新的NopEngine,参数false指定当NopEngine不为空时是否重新生成一个新的NopEngine。
- [MethodImpl(MethodImplOptions.Synchronized)]
- public static IEngine Initialize(bool forceRecreate)
- {
- if (Singleton<IEngine>.Instance == null || forceRecreate)
- {
- var config = ConfigurationManager.GetSection("NopConfig") as NopConfig;
- Debug.WriteLine("Constructing engine " + DateTime.Now);
- Singleton<IEngine>.Instance = CreateEngineInstance(config);
- Debug.WriteLine("Initializing engine " + DateTime.Now);
- Singleton<IEngine>.Instance.Initialize(config);
- }
- return Singleton<IEngine>.Instance;
- }
NopEngine 使用单例模式,在整个程序运行期间存在一个实例,代码首先会判断NopEngine是否为空,为空的话则根据web.config中配置的 NopConfig节点信息创建一个新的NopEngine实例,然后对该实例进行初始化操作。web.config中的配置信息如下:
- <configSections>
- <section name="NopConfig" type="Easy.Core.Configuration.NopConfig, Easy.Core" requirePermission="false" />
- </configSections>
- <NopConfig>
- <DynamicDiscovery Enabled="true" />
- <Engine Type="" />
- <Themes basePath="~/Themes/" />
- </NopConfig>
CreateEngineInstance函数中使用new NopEngine()创建了一个NopEngine实例,在NopEngine的构造函数处对Autofac的容器(Container)作了初始化,如下代码:
- public NopEngine(EventBroker broker, ContainerConfigurer configurer)
- {
- var config = ConfigurationManager.GetSection("NopConfig") as NopConfig;
- InitializeContainer(configurer, broker, config);
- }
- private void InitializeContainer(ContainerConfigurer configurer, EventBroker broker, NopConfig config)
- {
- var builder = new ContainerBuilder();
- _containerManager = new ContainerManager(builder.Build());
- configurer.Configure(this, _containerManager, broker, config);
- }
NopCommerce通过ContainerManager对容器做了一层封装,方便对其他类型的IOC框架的扩充和支持。Configure函数完成了所有依赖的注入,同时查找所有实现了IDependencyRegistrar接 口的类,并调用其Register方法,注册内容包括Http context、web helper、controller、data layer、plugin、cache manager、work context、services、settings、event consumers等等。
关于ContainerManager/ContainerConfigurer和IDependencyRegistrar是实现IOC的关键,下面对这两个部分做详细的讨论。
// todo:仍需继续分析具体实现
ContainerManager/ContainerConfigurer
- ContainerManagerContainerManager对依赖注入中使用的容器做了一层封装,提供了这些函数:
- AddComponent/AddComponentInstance/AddComponentWithParameters
- Resolve/ResolveAll/ResovleUnregistered
- UpdateContainer
DependencyRegistrar
- web helper
- controller
- data layer
- plugin
- cache manager
- work context
- services
- settings
- event consumers
from:aneasystone ==>http://www.cnblogs.com/aneasystone/archive/2012/08/27/2659176.html
IOC和DI
IOC中文名被称作控制反转(Inversion of Control),DI被称为依赖注入(Dependency Injection),可参考Martin Fowler的这篇文章来了解这两个概念:IoC容器和DependencyInjection模式。使用控制反转模式开发项目流程是先建立接口,然后再实现类,或许有人不习惯这样的开发方法,但在规模较大的软件架构中,这种方法却可以有效的降低类之间的互相依赖的情况,不但能增加架构的弹性,也能有效的降低软件的复杂度。
如果不考虑控制反转的情况,采用直接创建类,并直接在应用层调用该类,如此一来,应用层的对象就会与BLL(业务逻辑层)对象高度依赖,这样的依赖 会导致这两个类无法拆开,从而增加了这个类的维护难度,同时导致了单元测试难以进行。为了解决耦合度问题,从而引入了控制反转的概念。
Autofac介绍
Autofac是一款IOC框架,比较于其他的IOC框架,如Spring.NET、Unity、Castle等,它更显得轻量级,同时保证了高性能。它具有以下优点:
- 和C#语言联系紧密,可以使用C#语言的很多特性,譬如Lambda表达式等;
- 较低的学习曲线,只需了解IoC和DI的概念以及在何时需要使用它们即可;
- XML配置支持;
- 自动装配;
- 与ASP.NET MVC3集成;(Orchard也是使用Autofac实现IOC的)
在MVC3项目中使用Autofac
在MVC3工程中使用Autofac的最好也是最简单的方法是使用NuGet来安装Autofac.Mvc3,安装完成以后,在Global.asax的Application_Start方法中添加如下代码:
- protected void Application_Start()
- {
- var builder = new ContainerBuilder();
- builder.RegisterControllers(typeof(MvcApplication).Assembly);
- var container = builder.Build();
- DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
- // Other MVC setup...
这样就开启了Controller的依赖注入功能。其中的DependencyResolver是一个全局静态类,MVC3提供了对依赖注入的支 持,SetResolver函数用于设置使用哪个Resolver(解析器)来进行依赖注入,这里使用的是Autofac的依赖注入解析器。如果要使用自 己的解析器,必须在这里使用SetResolver函数设置。
1. 注册Controller
可以使用下面的方法对特定的Controller进行注册:
- var builder = new ContainerBuilder();
- builder.RegisterType<HomeController>().InstancePerRequest();
- 同时可以使用Autofac提供的RegisterControllers扩展方法来对程序集中所有的Controller一次性的完成注册:
- var builder = new ContainerBuilder();
- builder.RegisterControllers(Assembly.GetExecutingAssembly());
2. 注册Model Binder
与控制器的注册类似,模型绑定也可以再Global.asax.cs中注册。您可以通过如下操作完成整个程序集的注册:
- var builder = newContainerBuilder();
- builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
- builder.RegisterModelBinderProvider();
您也必须记住使用RegisterModelBinderProvider扩展方法来注册RegisterModelBinderProvider。这个方法用是Autofac对IModelBinderProvider接口的实现。
因为RegisterModelBinders扩展方法通过扫描程序集来添加模型绑定的,所以您需要指定IModelBuilder注册的目标类是什么类型。
- [ModelBinderType(typeof(string))]
- public class StringBinder : IModelBinder
- {
- public override object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)
- {
- //do implementation here
- }
- }
多行的ModelBuilderTypeAttribute实例可以添加到需要对个类型注册的类中。
3. 注入HTTP抽象类
- HttpContextBase
- HttpRequestBase
- HttpResponseBase
- HttpServerUtilityBase
- HttpSessionStateBase
- HttpApplicationStateBase
- HttpBrowserCapabilitiesBase
- HttpCachePolicyBase
- VirtualPathProvider
- builder.RegisterModule(newAutofacWebTypesModule());
4. 注入View page
- builder.RegisterSource(newViewRegistrationSource());
- public abstract class CustomViewPage : WebViewPage
- {
- public IDependencyDependency { get; set; }
- }
- public abstract class CustomViewPage : ViewPage
- {
- public IDependencyDependency { get; set; }
- }
- @inherits Example.Views.Shared.CustomViewPage
- <%@ PageLanguage="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="Example.Views.Shared.CustomViewPage" %>
5. 对Filter Attribute进行属性注入
- ContainerBuilder builder = new ContainerBuilder();
- builder.RegisterControllers(Assembly.GetExecutingAssembly());
- builder.Register(c => new Logger()).As<ILogger>().InstancePerHttpRequest();
- builder.RegisterFilterProvider();
- IContainer container = builder.Build();
- DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
- public class CustomActionFilter : ActionFilterAttribute
- {
- public ILogger Logger { get; set; }
- public override void OnActionExecuting(ActionExecutingContext filterContext)
- {
- Logger.Log("OnActionExecuting");
- }
- }
- public class CustomAuthorizeAttribute : AuthorizeAttribute
- {
- public ILogger Logger { get; set; }
- protected override bool AuthorizeCore(HttpContextBase httpContext)
- {
- Logger.Log("AuthorizeCore");
- return true;
- }
- }
- [CustomActionFilter]
- [CustomAuthorizeAttribute]
- public ActionResult Index()
- {
- // ...
- }
- 关于Autofac更多的信息,可以参考autofac在google code上的wiki文档:http://code.google.com/p/autofac/wiki/Mvc3Integration
NopCommerce是如何使用Autofac实现依赖注入的?
NopCommerce将所有和Autofac注入相关的工作都放到了EngineContext中,在Global.asax的Application_Start函数的第一句代码即是:
- //initialize engine context
- EngineContext.Initialize(false);
从这里开始EngineContext的初始化工作,初始化时会创建一个新的NopEngine,参数false指定当NopEngine不为空时是否重新生成一个新的NopEngine。
- [MethodImpl(MethodImplOptions.Synchronized)]
- public static IEngine Initialize(bool forceRecreate)
- {
- if (Singleton<IEngine>.Instance == null || forceRecreate)
- {
- var config = ConfigurationManager.GetSection("NopConfig") as NopConfig;
- Debug.WriteLine("Constructing engine " + DateTime.Now);
- Singleton<IEngine>.Instance = CreateEngineInstance(config);
- Debug.WriteLine("Initializing engine " + DateTime.Now);
- Singleton<IEngine>.Instance.Initialize(config);
- }
- return Singleton<IEngine>.Instance;
- }
NopEngine 使用单例模式,在整个程序运行期间存在一个实例,代码首先会判断NopEngine是否为空,为空的话则根据web.config中配置的 NopConfig节点信息创建一个新的NopEngine实例,然后对该实例进行初始化操作。web.config中的配置信息如下:
- <configSections>
- <section name="NopConfig" type="Easy.Core.Configuration.NopConfig, Easy.Core" requirePermission="false" />
- </configSections>
- <NopConfig>
- <DynamicDiscovery Enabled="true" />
- <Engine Type="" />
- <Themes basePath="~/Themes/" />
- </NopConfig>
CreateEngineInstance函数中使用new NopEngine()创建了一个NopEngine实例,在NopEngine的构造函数处对Autofac的容器(Container)作了初始化,如下代码:
- public NopEngine(EventBroker broker, ContainerConfigurer configurer)
- {
- var config = ConfigurationManager.GetSection("NopConfig") as NopConfig;
- InitializeContainer(configurer, broker, config);
- }
- private void InitializeContainer(ContainerConfigurer configurer, EventBroker broker, NopConfig config)
- {
- var builder = new ContainerBuilder();
- _containerManager = new ContainerManager(builder.Build());
- configurer.Configure(this, _containerManager, broker, config);
- }
NopCommerce通过ContainerManager对容器做了一层封装,方便对其他类型的IOC框架的扩充和支持。Configure函数完成了所有依赖的注入,同时查找所有实现了IDependencyRegistrar接 口的类,并调用其Register方法,注册内容包括Http context、web helper、controller、data layer、plugin、cache manager、work context、services、settings、event consumers等等。
关于ContainerManager/ContainerConfigurer和IDependencyRegistrar是实现IOC的关键,下面对这两个部分做详细的讨论。
// todo:仍需继续分析具体实现
ContainerManager/ContainerConfigurer
- ContainerManagerContainerManager对依赖注入中使用的容器做了一层封装,提供了这些函数:
- AddComponent/AddComponentInstance/AddComponentWithParameters
- Resolve/ResolveAll/ResovleUnregistered
- UpdateContainer
DependencyRegistrar
- web helper
- controller
- data layer
- plugin
- cache manager
- work context
- services
- settings
NopCommerce使用Autofac实现依赖注入的更多相关文章
- Autofac之依赖注入
这里主要学习一下Autofac的依赖注入方式 默认构造函数注入 class A { public B _b; public A() { } public A(B b) { this._b = b; } ...
- Web API(六):使用Autofac实现依赖注入
在这一篇文章将会讲解如何在Web API2中使用Autofac实现依赖注入. 一.创建实体类库 1.创建单独实体类 创建DI.Entity类库,用来存放所有的实体类,新建用户实体类,其结构如下: us ...
- NET Core源代码通过Autofac实现依赖注入
查看.NET Core源代码通过Autofac实现依赖注入到Controller属性 阅读目录 一.前言 二.使用Autofac 三.最后 回到目录 一.前言 在之前的文章[ASP.NET Cor ...
- SmartStore.Net、NopCommerce 全局异常处理、依赖注入、代码研究
以下是本人最近对NopCommerce和SmartStore.net部分代码的研究和总结,主要集中于:依赖注入.异常处理.对象映射.系统缓存.日志这些方面,供大家参考. NOP 3.8 /// < ...
- 我的NopCommerce之旅(7): 依赖注入(IOC/DI)
一.基础介绍 依赖注入,Dependency Injection,权威解释及说明请自己查阅资料. 这里简单说一下常见使用:在mvc的controller的构造方法中定义参数,如ICountryServ ...
- 查看.NET Core源代码通过Autofac实现依赖注入到Controller属性
一.前言 在之前的文章[ASP.NET Core 整合Autofac和Castle实现自动AOP拦截]中,我们讲过除了ASP.NETCore自带的IOC容器外,如何使用Autofac来接管IServi ...
- 【AutoFac】依赖注入和控制反转的使用
在开始之前首先解释一下我认为的依赖注入和控制反转的意思.(新手理解,哪里说得不正确还请指正和见谅) 控制反转:我们向IOC容器发出获取一个对象实例的一个请求,IOC容器便把这个对象实例“注入”到我们的 ...
- WebAPi使用Autofac实现依赖注入
WebAPi依赖注入 使用记录 笔记 1.NuGet包安装 2.控制器加入构造函数 3.Global.asax ----Application_Start 应用程序启动时 using Autofa ...
- Autofac 泛型依赖注入
using Autofac;using Autofac.Extensions.DependencyInjection;using Hangfire;using Microsoft.AspNetCore ...
随机推荐
- 【转】webgame前台开发总结--虽然是10年的文章,但是也有参考价值
一.webgame整个游戏流程: 1.预加载(打开游戏页面后,显示进度条,主要加载前期的登陆和创建角色资源,创建角色资源的加载可以放到进入创建角色界面的时候加载,因为玩家除了第一次进入游戏,其他时间基 ...
- phonegap 新窗口 WebView
自定义WebView窗口打开 import com.ap.work.QuickWeb public class QuickPlugin extends CordovaPlugin { /** * 新开 ...
- LINQ标准查询操作符(五)
十二.相等操作符 如果两个序列的对应元素相等且这两个序列具有相同数量的元素,则视这两个序列相等. SequenceEqual方法通过并行地枚举两个数据源并比较相应元素来判断两个序列是否相等.如果两个序 ...
- fdquery update
fdquery update this->FDQuery1->CachedUpdates; this->FDQuery1->UpdateOptions->KeyFiel ...
- Spark的发展历程
·2009年:Spark诞生于AMPLab.·2010年:开源.·2013年6月:Apache孵化器项目.·2014年2月:Apache顶级项目.·2014年2月:大数据公司Cloudera宣称加大S ...
- 如何在Centos上安装python3.4
Centos上面默认的Python版本是2.6,本文介绍如何安装3.4版本. 0.下载前准备 需要安装以下库,不然会有问题. yum -y install zlib-devel bzip2-devel ...
- ESP8266 TCP传输AT指令顺序
); //复位 ret = ESP8266_Cmd ( );//测试AT启动 ret = ESP8266_Cmd ( );//选择WIFI应用模式softAP+station //ret = ESP8 ...
- Ubuntu下Android编译环境的配置
从安装操作系统到编译程序结束,过程大致如下. 1. Ubuntu Linux操作系统安装软件包.使用 Ubuntu 14.04 Desktop系统.安装Linux系统到VMWare虚拟机上. 2. 完 ...
- HDU 5438 Ponds (DFS,并查集)
题意:给定一个图,然后让你把边数为1的结点删除,然后求连通块结点数为奇的权值和. 析:这个题要注意,如果删除一些结点后,又形成了新的边数为1的结点,也应该要删除,这是坑,其他的,先用并查集判一下环,然 ...
- JS、jqueryie6浏览器下使用js无法提交表单的解决办法
-----------------------JS.jqueryie6浏览器下使用js无法提交表单的解决办法---------------------------------------------- ...