一、基础介绍

  ——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. 大数相乘(hdu 1402)

    ------------------题目链接--------------------- 题目没啥说的,两个数相乘,fft,一发模板就AC,kuangbin模板大法好,不懂原理的小白也能体验AC. 个人 ...

  2. CopyOnWrite 策略

    CopyOnWrite 是用于解决并发读写的一种策略,在Write的时候对共享变量进行Copy,在副本上进行更新,再把更新好的副本原子性地替换原来的共享变量.写入时复制是一种优化策略,多个调用者同时访 ...

  3. NHibernate错误:Could not compile the mapping document的解决

    用动软代码生成器的NHibernate生成模板,生成一个“XML映射模板”,老是提示Could not compile the mapping document的问题. 各种的找,就是没找到问题. 后 ...

  4. Notice:Array to string conversion的问题

    如果后台或者前端输出这样的提示: Notice: Array to string conversion 原因是:用 echo  来输出数组,当然会报错,数组应该用print , print_r , 或 ...

  5. 1.1- 1.2 hive入门

    一.hive是什么 由Facebook开源用于解决海量结构化日志的数据统计: Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射成一张表, 并提供类SQL查询功能: 构建在Had ...

  6. Flutter实战视频-移动电商-14.首页_url_launcher一键拨打店长电话

    14.首页_url_launcher一键拨打店长电话 首页拨打电话的功能. 接收连个值,一个是店长的头像,一个是电话号码, 然后开始写我们的build方法.点击图片的时候要有一个拨打电话的动作.我们要 ...

  7. Laravel中的模板引擎Blade

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. 洛谷 - P2551 - 华夏60战斗机 - 简单dp

    https://www.luogu.org/problemnew/show/P2551 首先这道题没有给Hm的最大值,很坑,只能随便开一个100没想到还过了. 观察题目,发现虽然高度可以变化,但是速度 ...

  9. Xcode10更新报错:library not found for -lstdc++.6.0.9

    转载链接!:https://blog.csdn.net/timtian008/article/details/82792629 由于iPhone X Max 及iOS12系统的到来,必须升级xcode ...

  10. Codeforces Round #377 (Div. 2)A,B,C,D【二分】

    PS:这一场真的是上分场,只要手速快就行.然而在自己做的时候不用翻译软件,看题非常吃力非常慢,还有给队友讲D题如何判断的时候又犯了一个毛病,一定要心平气和,比赛也要保证,不要用翻译软件做题: Code ...