我的NopCommerce之旅(9): 编写Plugin实例
一、基础介绍
——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实例的更多相关文章
- 我的NopCommerce之旅(8): 路由分析
一.导图和基础介绍 本文主要介绍NopCommerce的路由机制,网上有一篇不错的文章,有兴趣的可以看看NopCommerce源码架构详解--对seo友好Url的路由机制实现源码分析 SEO,Sear ...
- [转]NopCommerce之旅: 应用启动
本文转自:http://www.cnblogs.com/devilsky/p/5359881.html 我的NopCommerce之旅(6): 应用启动 一.基础介绍 Global.asax 文件 ...
- 初探webpack之编写plugin
初探webpack之编写plugin webpack通过plugin机制让其使用更加灵活,以适应各种应用场景,当然也大大增加了webpack的复杂性,在webpack运行的生命周期中会广播出许多事件, ...
- 【小白的CFD之旅】13 敲门实例【续3】
接上文[小白的CFD之旅]12 敲门实例[续2] 4 Results4.1 计算监测图形4.2 Graphics4.2.1 壁面温度分布4.2.2 创建截面4.2.3 显示截面物理量4.2.4 Pat ...
- 【小白的CFD之旅】11 敲门实例【续】
主要内容: 接上文[小白的CFD之旅]10 敲门实例 2.4 Materials设置2.5 Cell Zone Conditions2.6 Boundary Conditons2.7 Dynamic ...
- [转]nopcommerce商城系统--如何编写一个插件
本文转自:http://www.cnblogs.com/ganqiyin/p/3680771.html 原址:http://www.nopcommerce.com/docs/77/how-to-wri ...
- nopcommerce商城系统--如何编写一个插件
原址:http://www.nopcommerce.com/docs/77/how-to-write-a-nopcommerce-plugin.aspx plug-in (或 plugin)是一个为更 ...
- 我的NopCommerce之旅(7): 依赖注入(IOC/DI)
一.基础介绍 依赖注入,Dependency Injection,权威解释及说明请自己查阅资料. 这里简单说一下常见使用:在mvc的controller的构造方法中定义参数,如ICountryServ ...
- 我的NopCommerce之旅(5): 缓存
一.基础介绍 1.什么是cache Web缓存是指一个Web资源(如html页面,图片,js,数据等)存在于Web服务器和客户端(浏览器)之间的副本. 2.为什么要用cache 即 ...
随机推荐
- cassandra 存储二进制data
Blob type The Cassandra blob data type represents a constant hexadecimal number defined as 0[xX](hex ...
- UVA-11892(组合游戏)
题意: 给n堆石子,每堆有ai个,每次可以取每堆中任意数目的石子;但是上一次操作的人没有将一堆全部取走,那么下一个人还要在那一堆取; 思路: 每次取到这堆就剩一个的策略; AC代码: #include ...
- hdu-5726 GCD(rmq)
题目链接: GCD Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Prob ...
- 关于“C++语言程序设计”书的一个类
class book{ char* title; int num_pages; int cur_page;public: book(const char* theTitle, ...
- [C++]变量存储类别,指针和引用,类与对象,继承与派生的一些摘要
C++中共有四种存储类别标识符:auto/static/register/extern 1.auto 函数或分程序内定义的变量(包括形参)可以定义为auto(自动变量).如果不指定存储类别,则隐式定义 ...
- oracle下 启动subversion命令 及 oracle相关服务启动备忘
linux shell下 svnserve - d -r + 目录 例如:svnserve -d -r /svn 启动 svn服务. 访问svn://192.168.0.120/kjcg 测试. ...
- Swift扩展
Swift中的「扩展」(extensions)和OC中的categories类似,只是Swift中的「扩展」没有名字.Swift中的「扩展」可以向一个已有的类/结构体/枚举类型添加新功能,这包括在没有 ...
- MongoDB搭建ReplSet复制集群
MongoDB的复制集是一个主从复制模式 又具有故障转移的集群,任何成员都有可能是master,当master挂掉用会很快的重新选举一个节点来充当master. 复制集中的组成主要成员 Primary ...
- bzoj 5092 分割序列 —— 高维前缀和
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5092 首先,处理出异或前缀和 s[i],i 位置的答案就是 s[j] + s[j]^s[i] ...
- 屏蔽iframe中超链接
<style type="text/css"> .mask { position: absolute; width: 290px; height: 96px; z-in ...