nopcommerce中文网

nopcommerce是国外asp.net领域一个高质量的b2c开源项目,基于EntityFramework和MVC开发,QQ群1:75272942(2000人超级群,已满) QQ群2:640322459

导航 - 搜索

NopCommerce是如何使用Autofac实现依赖注入的?

IOC和DI

IOC中文名被称作控制反转(Inversion of Control),DI被称为依赖注入(Dependency Injection),可参考Martin Fowler的这篇文章来了解这两个概念:IoC容器和DependencyInjection模式。使用控制反转模式开发项目流程是先建立接口,然后再实现类,或许有人不习惯这样的开发方法,但在规模较大的软件架构中,这种方法却可以有效的降低类之间的互相依赖的情况,不但能增加架构的弹性,也能有效的降低软件的复杂度。

如果不考虑控制反转的情况,采用直接创建类,并直接在应用层调用该类,如此一来,应用层的对象就会与BLL(业务逻辑层)对象高度依赖,这样的依赖会导致这两个类无法拆开,从而增加了这个类的维护难度,同时导致了单元测试难以进行。为了解决耦合度问题,从而引入了控制反转的概念。

Autofac介绍

 Autofac是一款IOC框架,比较于其他的IOC框架,如Spring.NET、Unity、Castle等,它更显得轻量级,同时保证了高性能。它具有以下优点:

  1. 和C#语言联系紧密,可以使用C#语言的很多特性,譬如Lambda表达式等;
  2. 较低的学习曲线,只需了解IoC和DI的概念以及在何时需要使用它们即可;
  3. XML配置支持;
  4. 自动装配;
  5. 与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抽象类

MVC集成的Autofac模块将会为HTTP抽象类添加HTTP 请求的生命收起范围内的注册。包括依稀抽象类:
  • HttpContextBase
  • HttpRequestBase
  • HttpResponseBase
  • HttpServerUtilityBase
  • HttpSessionStateBase
  • HttpApplicationStateBase
  • HttpBrowserCapabilitiesBase
  • HttpCachePolicyBase
  • VirtualPathProvider
需要使用上面的抽象应该使用容器的RegisterModule方法来添加AutofacWebTypesModule
builder.RegisterModule(newAutofacWebTypesModule());

4. 注入View page

您可以通过在容器创建之前添加ViewRegistrationSource 到容器中使属性注入来使MVC页面可用。
builder.RegisterSource(newViewRegistrationSource());
您的viewpage必须继承MVC类中用于创建,当使用Razor试图引擎时将需要继承WebViewPage类:
public abstract class CustomViewPage : WebViewPage
{
    public IDependencyDependency { getset; }
}
当使用的是webform的试图引擎时,ViewPage,ViewMasterPage和ViewUserControl类都得到相应的支持。
public abstract class CustomViewPage : ViewPage
{
    public IDependencyDependency { getset; }
}
必须确保您实际的试图页面继承了您自定义的基类。在Razor视图引擎.cshtml中可以使用@inherits指令来实现:
@inherits Example.Views.Shared.CustomViewPage
使用webform时可以做如下设置
<%@ PageLanguage="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="Example.Views.Shared.CustomViewPage" %>

5. 对Filter Attribute进行属性注入

为过滤器使用属性注入必须在容器创建之前调用RegisterFilterProvider方法,并将其传到AutofacDependencyResolver
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 { getset; }
 
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Logger.Log("OnActionExecuting");
    }
}
下面是类似用户验证过滤器的自定义特性
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    public ILogger Logger { getset; }
 
    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

nopCommerce的源代码结构和架构分析

编写本文档是为了向程序员说明nopcommerce的解决方案结构,亦是程序员开发nopcommerce的居家必备良书。首先 nopcommerce的源代码很容易拿到,它是开源的,所以你可以直接到网上下载。 在你打开VS以后项目和文件夹都会完整列出来,我们建议你在看此文档的同时也打开你的VS来浏览项目和文件。

绝大多数的项目,目录和文件都顾名思义,你可以从名字就大概知道是做什么的。比如Nop.Plugin.Payments.PayPalStandard这个我都不用看项目代码就能猜到做什么的。
\Libraries\Nop.Core
Nop.Core项目包含nopcommerce的一系列核心类如缓存,事件,辅助类和业务对象(如订单和客户实体类)
\Libraries\Nop.Data
Nop.Data 项目包含一系列的数据访问类和方法以从数据库或其他数据媒介读取和保存数据。它也有助于把数据访问逻辑和你的业务对象分离。 nopcommerce使用Entity Framework (EF) Code-First方法,允许你在nopcommerce代码中定义实体 (所有的核心实体类都在Nop.Core中定义),再让EF生成数据库,这就是为什么会叫Code-First。你接下来可以用LINQ来查询对象,它自 己会把查询转换为SQL语句并在数据库里执行。nopcommerce拥有牛B的API让你完全定制持久映射,你可以在这儿和这儿找到Code- First的资料。
\Libraries\Nop.Services
此项目包含一系列的核心服务,业务逻辑,验证,如果有数据的话还有数据的计算方法,也就是传说中的业务访问层(BAL)

\Plugins\ 文件夹中的那些项目

Plugins 是VS的解决方案文件夹,硬盘中它是在你解决方案的根目录下。由于项目在编译时的输入路径是”..\..\Presentation \Nop.Web\Plugins\{Group}.{Name}\”,这样插件的DLL会自动地放到 \Presentation\Nop.Web\Plugins\文件夹中,用来放置已部署插件。这样也能让插件包含静态文件比如CSS或JS,就不用在项 目之间拷贝这些文件了。

\Presentation\Nop.Admin

Nop.Admin是一MVC项目,如果你还从没用过ASP.NET MVC,请猛击这儿有更多信息。可能你已经猜到这是表示层中的管理后台,你可以在 \Presentation\Nop.Web\Administration文件夹中找到它,此项目不能运行。

\Presentation\Nop.Web

Nop.Web也是一MVC项目,前台网店的表示层,这个才是你真正要跑起来的项目,它也是整个应用程序的起始项目。

\Presentation\Nop.Web.Framework

Nop.Web.Framework是一个表示层的类库项目,包括可以让后台和前台使用的一些共用的展示功能。

\Test\Nop.Core.Tests

Nop.Core.Tests是Nop.Core的测试项目

\Test\Nop.Data.Tests

Nop.Data.Tests是Nop.Data的测试项目

\Test\Nop.Services.Tests

Nop.Services.Tests是 Nop.Services的测试项目

\Test\Nop.Tests

Nop.Tests是一个类库,包含其它测试项目中要用的一共有类和辅助方法,此项目不包含任何测试用例

如何编写nopCommerce插件

插件(Plug-in,又叫addin、add-in、addon或add-on)是一种电脑程序,通过和应用程序的互动,用来替应用程序增加一些所需要的特定的功能。(Wikipedia)

插 件用来扩展nopCommerce的功能,nopcommcer有多种类型的插件。比如支付方式中的paypal,税率供应商,配送计算方式 (UPS,USP,Fedex),小部件(live chat功能)等等。nopCommerce本身也自带了很多不同的插件。你可以在官网上搜索是否已经有人上传了满足你需要的插件。如果没有,哥这就手把 手带你编写一个出来。

插件结构,所用文件,所在位置

1. 你第一件事就是要在解决方案中新建一个“类库”项目。最好的办法是把插件都放在解决方案根目录(不过小心不要和Nop.Web下边的 plugins目录搞混了,那儿是放已布置插件的),而且最好把插件也都放在解决方案目录的plugin目录中(关于更多解决方案文件夹的信息,请猛击此处

最 好以这种方法来命名:”Nop.Plugin.{Group}.{Name}”。{Group}是你插件的分类(比如支付),{Name}是你的 插件名(比如”AuthorizeNet”),那么Authorize.NET的支付插件就会有这样的名 字:Nop.Plugin.Payments.AuthorizeNet。

2.一旦建立了插件项目,把输入路径改为”..\.. \Presentation\Nop.Web\Plugins\{Group}.{Name} \”,比如 Authorize.NET 支付插件就会有这样的输入路径: “..\..\Presentation\Nop.Web\Plugins\Payments.AuthorizeNet\”。搞定以后,对应的插件 DLL就会被拷贝到 \Presentation\Nop.Web\Plugins\ 文件夹,nopCommerce内核会搜索此文件夹。

a.在项目菜单,点击属性
b.选择生成选项卡
c.点击输入路径旁边的浏览按钮选择一个输入目录

你要在debug和release模式下都要做此步骤。

3.下一步你就要为你的每一个插件建立一个Description.txt,此文件包含描述插件的信息。你可以从其它插件目录中拷出来。比如Authorize.NET支付插件的Description.txt就有如下内容:

Group: Payment methods FriendlyName: Credit Card SystemName: Payments.AuthorizeNet Version: 1.00 SupportedVersions: 2.30 Author: nopCommerce team DisplayOrder: 1 FileName: Nop.Plugin.Payments.AuthorizeNet.dll  其实所有的信息你都能看懂,不过有一些注意事项。SystemName必须唯一。Version字段是你插件的版本号,你可以将它设置为你喜欢的任何值。SupportedVersions可以包含一个由逗号分隔的(确保nopCommerce当前版本包含在此列表中,否则此插件没戏)支持版本清单。FileName是用这个格式:Nop.Plugin.{Group}.{Name}.dll(是你插件的assembly文件名)。要确保此文件的“拷贝到输入目录”属性是“Copy if newer”


4. 所需的最后一个步骤是创建一个类实现IPlugin接口(Nop.Core.Plugins命名空间)。nopCommerce有 BasePlugin类已经实现了一些IPlugin方法,这样你就不用苦逼地再写一遍。nopCommerce还提供一些从IPlugin派生特定的接 口。例如,俺们有“IPaymentMethod”接口,用于创建新的付款插件,它包含了一些特定的用于付款的方法如ProcessPayment()或 GetAdditionalHandlingFee()。nopCommerce目前有以下特定的插件接口:
IExternalAuthenticationMethod. 用来建立外部认证方法如 Facebook, Twitter, OpenID, etc.
IWidgetPlugin. 让你可以创建小部件,小部件在你网站的某些地方出现,如左边的Live chat框
IExchangeRateProvider. 用于获得货币汇率.
IDiscountRequirementRule. 允许你创建新的折扣规则比如”帐单寄到的国家必须是……“
ISMSProvider. 短信提供商,让你可以在下单时收到短信通知。
IPaymentMethod. 用于处理支付流程的插件。
IPromotionFeed. 这些插件用于向Froogle或PriceGrabber提供产品信息
IShippingRateComputationMethod..这些插件是用于获取可用的配送方法和正确的运费。例如,UPS,UPS,FEDEX等。
ITaxProvider. 税率提供商用于获取税率。

处理请求。控制器,模型和视图。

现 在你可以在Admin area > Configuration > Plugins看到我们的插件了,不过正如你所想,这个杯具的插件啥都不能做,甚至连个配置的界面都没有。现在让我们来创建一个配置页面。我们现在需要做 的是创建一个控制器,模型和视图。

  1. MVC控制器负责响应对一个ASP.NET MVC网站的请求。每个浏览器请求被映射到一个特定的控制器。
  2. 一个视图包含被发送到浏览器的HTML标记和内容。视图是相当于一个ASP.NET MVC应用程序的页面。
  3. 一个MVC模型包含视图或控制器以外的所有应用程序逻辑。

关于MVC模式在这里你可以找到更多的信息。

那么,我们可以开工了:

创建模型。新插件中加入一个Models文件夹,然后按你需要新加入一个模型类。
创建视图。在插件项目中新加一个Views文件夹,再在里边添加一个{Name}文件夹,此处{Name}是指你的插件名。然后再添加一个Configure.cshtml文件。很重要的一点:此视图应该要注明是嵌入资源。
创 建控制器。在插件项目中新加一个controller文件夹,再新加一个控制器类。最好的命名办法是像{Group} {Name}Controller.cs这样如PaymentAuthorizeNetController。再好好地命名一个action方法用于配 置。哥叫它“Configure”。准备一个模型类并将其传给这个视图:Nop.Plugin.{Group}.{Name}.Views. {Group}{Name}.Configure,即那个嵌入视图。比如你在Authorize.NET支付插件中的 PaymentAuthorizeNetController实现你就会比较清楚。

提示一:从其它插件项目中拷贝web.config到你项目里来,这样在做视图的时候有智能感知(老丁:啊?真的么?这和拷文件有什么关系?)。智能感知即微软的自动完成亮点。

提示二:搞定以上步骤最简单的办法是直接把其它插件项目拷贝过来,然后文件和文件夹改名。

提示三:如果你想限制后台(店主)控制器的一些action方法,只用在方法上加[AdminAuthorize]属性即可。

提示四:接下来要确保所有第三方的程序集引用的“拷贝到本地”属性设为false,这样可以减小部署包的大小。

比如Authorize.NET插件的项目结构会如下图:

路由

现在我们要为插件注册相应的路由。ASP.NET路由用于把浏览器发送的请求映射成MVC控制器相应的action方法,接下来的步骤你会读到很多详细关于路由的信息。

1. 新建如下文件:RouteProvider.cs,它会向nopcommerce告知关于插件路由信息。比如下边的RouteProvider添加了一个 新的路由,可以通过浏览器路径http://www.yourStore.com/Plugins/PaymentAuthorizeNet /Configure来访问:

public partial class RouteProvider : IRouteProvider {         public void RegisterRoutes(RouteCollection routes)         {             routes.MapRoute("Plugin.Payments.AuthorizeNet.Configure",                  "Plugins/PaymentAuthorizeNet/Configure",                  new { controller = "PaymentAuthorizeNet", action = "Configure" },                  new[] { "Nop.Plugin.Payments.AuthorizeNet.Controllers" }             );         }         public int Priority         {             get             {                 return 0;             }         } }

2. 一些特写的插件接口(像上边讲的)和“IMiscPlugin”接口有一个方法“GetConfigurationRoute”。它应该向控制器返回一个 用于插件后台配置的路由。实现你插件的“GetConfigurationRoute”方法,可以告知nopCommerce你插件的后台配置路由是什 么。如果你插件不需要后台配置,那么此方法将返回NULL,比如下边这样:

public void GetConfigurationRoute(out string actionName,
out string controllerName,
out RouteValueDictionary routeValues)
{
actionName = “Configure”;
controllerName = “PaymentAuthorizeNet”;
routeValues = new RouteValueDictionary()
{
{ “Namespaces”, “Nop.Plugin.Payments.AuthorizeNet.Controllers” },
{ “area”, null }
};
}

只要你有这个配置方法,插件安装以后你就能在Admin > Configuration > Plugins找到一个配置链接。

处理“安装”和“卸载”方法

这是可选步骤。一些插件需要有一定的安装逻辑,比如插件要添加一些本地资源数据。在你的IPlugin实现中(大多数情况下是直接从BasePlugin类继承下来),重载以下方法:

1. Install:在插件安装时会调用此方法,你可以在此初始化任何设置,添加新的本地资源数据或添加新的数据库表(如果需要的话)

2.Uninstall:在卸载插件时会调用此方法。

重要说明:如果你重载这些方法,不要隐藏基类的实现。比如重载”Install”的时候要记得调用base.Install(),Authorize.NET的install方法如下:

public override void Install()
{
var settings = new AuthorizeNetPaymentSettings()
{
UseSandbox = true,
TransactMode = TransactMode.Authorize,
TransactionKey = “123″,
LoginId = “456″
};
_settingService.SaveSetting(settings);

base.Install();
}

提示:已安装的插件列表可以在\App_Data\InstalledPlugins.txt找到,这个列表是在安装的时候创建的。

升级nopCommerce可能会让插件挂掉

一 些插件可能在新版本的nopCommerce中挂掉无法工作。如果在升级后有问题,请删除插件再到nopCommerce官网看看是否有些版本的 插件下载。大部分的插件作者都会把他们的插件升级到新的版本,不过少数插件并不会跟随着一起升级从而不再支持新版本。不过大多数情况下,你可以打开相应的 Description.txt文件并编辑SupportedVersions字段。

小结

希望此文能让你开始nopCommerce的插件之旅并搞个出类拔萃的插件。

nopcommerce是什么

简介

nopcommerce是国外的一个高质量的开源b2c网站系统,基于 EntityFramework4.0和MVC3.0,使用Razor模板引擎,有很强的插件机制,包括支付配送功能都是通过插件来实现的,基于xml的 多语言版本,非常灵活的语言切换功能,包括在后台都能同时编辑产品的中英文属性,非常适合做外贸,优秀超前的程序架构,性能也非常强大,自定义的产品名称 和分类又有很好的seo优化。综合能力远远高于国内的一些程序架构糟糕的.net商城程序,是二次开发和大型b2c架构的首选。

nopCommerce 具有的功能,帮助您启动功能强大的电子商务解决方案的能力,财富。本页面提供与它的特性和功能的快照你。我们已要求所有建立一个成功的电子商务商店的必要 工具。我们总是增加的特点nopCommerce名单,请查看我们的路线图,或与我们联系,了解在这条管道的。

其中一个nopCommerce主要特点是它的可插入模块/层状结构,允许更多的功能和演示内容将动态添加到应用程序在运行时。这可插入的模块化架构可以轻松地创建和管理网站。

综合型录功能

支持类和制造商

类别也可以完全嵌套到所需要的(分类别中的任何级别)

产品可以映射到多个类别或制造商

产品可以映射到多个类别或制造商

匿名结帐

支持套件产品,例如构建自己的电脑()

多语言支持

多币种支持

测量重量,尺寸测量

实时货币汇率(央行)

SSL支持

出口/进口(XML的时,Excel)

PDF格式秩序收据

全定制设计的100%使用模板

可配置允许的国家名单

登记

计费

航运

W3C的规定(的XHTML)

产品特点

产品属性(如颜色,大小)

每个产品支持多种图像

自动图像大小调整

产品支持下载

对产品文字选项(如要求对产品的缩写字母组合,要求客户对产品定制文本等名称)

支持简单的产品(如书籍)或变种产品

支持销售价格

产品搜索

特色产品,销售产品或新产品

库存跟踪

禁用购买特定产品的按钮

产品规格(如处理器,内存,显示卡)

比较产品功能(如果已启用)