一、基础介绍

  ——In computing, a plug-in (or plugin) is a set of software components that add specific abilities to a larger software application (Wikipedia).

  Plugin,即插件,用来做NopCommerce的功能扩展。NopCommerce源码本身提供了一些插件供参考使用。本篇文章通过阅读官方文档进行实践总结,主要讲解如何编写一个数据持久化的NopCommerce插件。

二、效果展示

  当打开前台产品详细时,系统会自动追踪并记录用户访问的产品信息、访问的用户信息及其IP地址信息等。

  

三、编写步骤

  1.新建项目,项目名为Nop.Plugin.Other.ProductViewTracker,注意项目位置需统一放置在..\plugins\下,与输出位置保持统一。

  

  2.添加Description.txt文件,该文件为必备文件,且格式需保持统一。该文件描述插件相关信息,并作为系统识别插件依据。

  

  3.添加必要的文件夹,名称可根据个人习惯,这里为保持命名规则统一,命名如下Controllers、Data、Domain、Services。

  

  4.添加dll引用,且设置属性"Copy Local"为False。本项目引用如图所示。

   

  5.添加实体类及其数据库映射,添加数据库访问上下文。

    5.1 实体类TrackingRecord,继承基类BaseEntity

 using Nop.Core;

 namespace Nop.Plugin.Other.ProductViewTracker.Domain
{
public class TrackingRecord : BaseEntity
{
public virtual int ProductId { get; set; }
public virtual string ProductName { get; set; }
public virtual int CustomerId { get; set; }
public virtual string IpAddress { get; set; }
public virtual bool IsRegistered { get; set; }
}
}

    5.2 数据库表映射类TrackingRecordMap,继承EntityTypeConfiguration<T>

 using Nop.Plugin.Other.ProductViewTracker.Domain;
using System.Data.Entity.ModelConfiguration; namespace Nop.Plugin.Other.ProductViewTracker.Data
{
public class TrackingRecordMap : EntityTypeConfiguration<TrackingRecord>
{
public TrackingRecordMap()
{
ToTable("ProductViewTracking"); HasKey(m => m.Id);
Property(m => m.ProductId);
Property(m => m.ProductName).HasMaxLength();
Property(m => m.IpAddress);
Property(m => m.CustomerId);
Property(m => m.IsRegistered);
}
}
}

    5.3 数据库访问上下文,安装插件时生成并执行建表脚本,卸载插件时删除该表

 using Nop.Data;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using Nop.Core;
using System.Data.Entity.Infrastructure; namespace Nop.Plugin.Other.ProductViewTracker.Data
{
public class TrackingRecordObjectContext : DbContext, IDbContext
{
public TrackingRecordObjectContext(string nameOrConnectionString) : base(nameOrConnectionString) { } #region Implementation of IDbContext public bool AutoDetectChangesEnabled
{
get
{
throw new NotImplementedException();
} set
{
throw new NotImplementedException();
}
} public bool ProxyCreationEnabled
{
get
{
throw new NotImplementedException();
} set
{
throw new NotImplementedException();
}
} public void Detach(object entity)
{
throw new NotImplementedException();
} public int ExecuteSqlCommand(string sql, bool doNotEnsureTransaction = false, int? timeout = default(int?), params object[] parameters)
{
throw new NotImplementedException();
} public IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : BaseEntity, new()
{
throw new NotImplementedException();
} public IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters)
{
throw new NotImplementedException();
} public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
{
return base.Set<TEntity>();
} protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new TrackingRecordMap()); base.OnModelCreating(modelBuilder);
} #endregion public string CreateDatabaseInstallationScript()
{
return ((IObjectContextAdapter)this).ObjectContext.CreateDatabaseScript();
} public void Install()
{
Database.SetInitializer<TrackingRecordObjectContext>(null); Database.ExecuteSqlCommand(CreateDatabaseInstallationScript());
SaveChanges();
} public void Uninstall()
{
var dbScript = "DROP TABLE ProductViewTracking";
Database.ExecuteSqlCommand(dbScript);
SaveChanges();
}
}
}

  6.添加业务服务类。

    6.1 服务接口

 using Nop.Plugin.Other.ProductViewTracker.Domain;

 namespace Nop.Plugin.Other.ProductViewTracker.Services
{
public interface IViewTrackingService
{
/// <summary>
/// Logs the specified record.
/// </summary>
/// <param name="record">The record.</param>
void Log(TrackingRecord record);
}
}

    6.2 业务服务类

 using Nop.Core.Data;
using Nop.Plugin.Other.ProductViewTracker.Domain; namespace Nop.Plugin.Other.ProductViewTracker.Services
{
public class ViewTrackingService : IViewTrackingService
{
private readonly IRepository<TrackingRecord> _trackingRecordRepository; public ViewTrackingService(IRepository<TrackingRecord> trackingRecordRepository)
{
_trackingRecordRepository = trackingRecordRepository;
} public void Log(TrackingRecord record)
{
_trackingRecordRepository.Insert(record);
}
}
}

  7.实现依赖注入的注册接口。

 using Nop.Core.Infrastructure.DependencyManagement;
using Autofac;
using Nop.Core.Configuration;
using Nop.Core.Infrastructure;
using Nop.Plugin.Other.ProductViewTracker.Services;
using Nop.Web.Framework.Mvc;
using Nop.Plugin.Other.ProductViewTracker.Data;
using Nop.Data;
using Nop.Plugin.Other.ProductViewTracker.Domain;
using Nop.Core.Data;
using Autofac.Core; namespace Nop.Plugin.Other.ProductViewTracker
{
public class DependencyRegistrar : IDependencyRegistrar
{
private const string CONTEXT_NAME = "nop_object_context_product_view_tracker"; public void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config)
{
builder.RegisterType<ViewTrackingService>().As<IViewTrackingService>().InstancePerLifetimeScope(); //data context
this.RegisterPluginDataContext<TrackingRecordObjectContext>(builder, CONTEXT_NAME); //override required repository with our custom context
builder.RegisterType<EfRepository<TrackingRecord>>()
.As<IRepository<TrackingRecord>>()
.WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT_NAME))
.InstancePerLifetimeScope();
} public int Order
{
get { return ; }
}
}
}

  8.添加MVC Controller。

 using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Customers;
using Nop.Core.Plugins;
using Nop.Plugin.Other.ProductViewTracker.Domain;
using Nop.Plugin.Other.ProductViewTracker.Services;
using Nop.Services.Catalog;
using Nop.Web.Framework.Controllers;
using System.Web.Mvc; namespace Nop.Plugin.Other.ProductViewTracker.Controllers
{
public class TrackingController : BasePluginController
{
private readonly IProductService _productService;
private readonly IViewTrackingService _viewTrackingService;
private readonly IWorkContext _workContext; public TrackingController(IWorkContext workContext,
IViewTrackingService viewTrackingService,
IProductService productService,
IPluginFinder pluginFinder)
{
_workContext = workContext;
_viewTrackingService = viewTrackingService;
_productService = productService;
} [ChildActionOnly]
public ActionResult Index(int productId)
{
//Read from the product service
Product productById = _productService.GetProductById(productId); //If the product exists we will log it
if (productById != null)
{
//Setup the product to save
var record = new TrackingRecord();
record.ProductId = productId;
record.ProductName = productById.Name;
record.CustomerId = _workContext.CurrentCustomer.Id;
record.IpAddress = _workContext.CurrentCustomer.LastIpAddress;
record.IsRegistered = _workContext.CurrentCustomer.IsRegistered(); //Map the values we're interested in to our new entity
_viewTrackingService.Log(record);
} //Return the view, it doesn't need a model
return Content("");
}
}
}

  9.实现路由接口。

 using Nop.Web.Framework.Mvc.Routes;
using System.Web.Mvc;
using System.Web.Routing; namespace Nop.Plugin.Other.ProductViewTracker
{
public class RouteProvider : IRouteProvider
{
public int Priority
{
get
{
return ;
}
} public void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("Nop.Plugin.Other.ProductViewTracker.Log",
"tracking/productviews/{productId}",
new { controller = "Tracking", action = "Index" },
new[] { "Nop.Plugin.Other.ProductViewTracker.Controllers" }
);
}
}
}

  10.添加插件类,继承插件基类,重载安装和卸载方法。

 using Nop.Core.Plugins;
using Nop.Plugin.Other.ProductViewTracker.Data; namespace Nop.Plugin.Other.ProductViewTracker
{
public class ProductViewTrackerPlugin : BasePlugin
{
private readonly TrackingRecordObjectContext _context; public ProductViewTrackerPlugin(TrackingRecordObjectContext context)
{
_context = context;
} public override void Install()
{
_context.Install();
base.Install();
} public override void Uninstall()
{
_context.Uninstall();
base.Uninstall();
}
}
}

  11.在NopCommerce的前台,加入插件的应用代码。这里,我们在页面Nop.Web\Views\Product\ProductTemplate.Simple.cshtml中插入应用代码。

@Html.Action("Index", "Tracking", new { productId = Model.Id })

  如图

  

我的NopCommerce之旅(9): 编写Plugin实例的更多相关文章

  1. 我的NopCommerce之旅(8): 路由分析

    一.导图和基础介绍 本文主要介绍NopCommerce的路由机制,网上有一篇不错的文章,有兴趣的可以看看NopCommerce源码架构详解--对seo友好Url的路由机制实现源码分析 SEO,Sear ...

  2. [转]NopCommerce之旅: 应用启动

    本文转自:http://www.cnblogs.com/devilsky/p/5359881.html 我的NopCommerce之旅(6): 应用启动   一.基础介绍 Global.asax 文件 ...

  3. 初探webpack之编写plugin

    初探webpack之编写plugin webpack通过plugin机制让其使用更加灵活,以适应各种应用场景,当然也大大增加了webpack的复杂性,在webpack运行的生命周期中会广播出许多事件, ...

  4. 【小白的CFD之旅】13 敲门实例【续3】

    接上文[小白的CFD之旅]12 敲门实例[续2] 4 Results4.1 计算监测图形4.2 Graphics4.2.1 壁面温度分布4.2.2 创建截面4.2.3 显示截面物理量4.2.4 Pat ...

  5. 【小白的CFD之旅】11 敲门实例【续】

    主要内容: 接上文[小白的CFD之旅]10 敲门实例 2.4 Materials设置2.5 Cell Zone Conditions2.6 Boundary Conditons2.7 Dynamic ...

  6. [转]nopcommerce商城系统--如何编写一个插件

    本文转自:http://www.cnblogs.com/ganqiyin/p/3680771.html 原址:http://www.nopcommerce.com/docs/77/how-to-wri ...

  7. nopcommerce商城系统--如何编写一个插件

    原址:http://www.nopcommerce.com/docs/77/how-to-write-a-nopcommerce-plugin.aspx plug-in (或 plugin)是一个为更 ...

  8. 我的NopCommerce之旅(7): 依赖注入(IOC/DI)

    一.基础介绍 依赖注入,Dependency Injection,权威解释及说明请自己查阅资料. 这里简单说一下常见使用:在mvc的controller的构造方法中定义参数,如ICountryServ ...

  9. 我的NopCommerce之旅(5): 缓存

    一.基础介绍 1.什么是cache      Web缓存是指一个Web资源(如html页面,图片,js,数据等)存在于Web服务器和客户端(浏览器)之间的副本. 2.为什么要用cache      即 ...

随机推荐

  1. 在一个form表单中根据不同按钮实现多个action事件

    <form id="writeForm" method="post"> <div class="write-btn-tj" ...

  2. 数组(Array)的初始化

    如果这样: private static int unsorted[]; for(int i = 1 ; i < 8 ; i ++ ) unsorted[i] = 1 ; 是会报NullPoin ...

  3. 禁用ubuntu 客人会话

    sudo vi /usr/share/lightdm/lightdm.conf.d/50-guest-wrapper.conf 添加: allow-guest=false 重启.

  4. bzoj4804

    莫比乌斯反演 我不会推线性筛 留坑

  5. AspNetPager样式以及属性帮助文档

    帮助文档地址:http://www.webdiyer.com/AspNetPagerDocs/index.html 应用样式:http://www.webdiyer.com/AspNetPagerDe ...

  6. OS__信号量(semaphore)PV操作

    信号量的概念 1.信号量的类型定义 信号量(semaphore)的数据结构为记录型数据结构一个值和一个指针,指针指向等待该信号量的下一个进程.信号量的值与相应资源的使用情况有关,在操作系统中,信号量用 ...

  7. 【Linux学习】Linux系统管理2—作业调度

    Linux系统管理2-作业调度 at: 作业仅执行一次就从系统工作队列中取消 语法 denny@ubuntu:~$ at [-m] TIME                     → 作业命令at ...

  8. 微信小程序开发之页面注册

    页面Page是object Page({  data:{    String1  },  onLoad:function(options){    // 生命周期函数--监听页面加载 一个页面只会调用 ...

  9. Flutter实战视频-移动电商-03.底部导航栏制作

    03.底部导航栏制作 material是谷歌退出的 还有另外的一种:cupertino是IOS的风格 我们底部的导航栏,静态的widget是不合适的,这垃圾我们用到动态的widget 这重新改成动态的 ...

  10. fitnesse(gradle构建)安装步骤

    1.安装jdk.ant.gradle(参考http://www.cnblogs.com/274914765qq/p/4401525.html) 2.下载Fitnesse https://github. ...